1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
16:
17: 18: 19: 20: 21:
22: class Pinoco_Vars implements IteratorAggregate, ArrayAccess, Countable, Pinoco_ArrayConvertible
23: {
24: private $_vars;
25: private $_default_val;
26: private $_loose;
27:
28: 29: 30:
31: public function __construct()
32: {
33: $this->_vars = array();
34: $this->_default_val = null;
35: $this->_loose = false;
36: }
37:
38: 39: 40: 41: 42: 43:
44: public static function fromArray($src)
45: {
46: $self = new Pinoco_Vars();
47: $self->import($src);
48: return $self;
49: }
50:
51: 52: 53: 54: 55: 56: 57:
58: public static function wrap(&$srcref)
59: {
60: if (!is_array($srcref)) {
61: throw new InvalidArgumentException("Non array variable was given.");
62: }
63: $self = new Pinoco_Vars();
64: $self->_vars = &$srcref;
65: return $self;
66: }
67:
68: 69: 70: 71: 72: 73: 74:
75: public function get($name, $default=Pinoco_OptionalParam::UNSPECIFIED)
76: {
77: if (array_key_exists($name, $this->_vars)) {
78: $r = $this->_vars[$name];
79: if ($r instanceof Pinoco_ValueProxy) {
80: $r = $r->fetch();
81: }
82: return $r;
83: }
84: else {
85: return Pinoco_OptionalParam::isSpecifiedBy($default) ? $default : $this->_default_val;
86: }
87: }
88:
89: 90: 91: 92: 93: 94: 95:
96: public function rget($expression, $default=Pinoco_OptionalParam::UNSPECIFIED)
97: {
98: $default = Pinoco_OptionalParam::isSpecifiedBy($default) ? $default : $this->_default_val;
99: $es = explode('/', $expression);
100: $v = $this;
101: while (count($es) > 0) {
102: $name = trim(array_shift($es));
103: if ($name === "") {
104: continue;
105: }
106: if ($v instanceof Pinoco_ArrayConvertible) {
107: $v = $v->get($name, $default);
108: }
109: elseif (is_object($v)) {
110: if (property_exists($v, $name)) {
111: $v = $v->$name;
112: }
113: else {
114: return $default;
115: }
116: }
117: elseif (is_array($v)) {
118: if (array_key_exists($name, $v)) {
119: $v = $v[$name];
120: }
121: else {
122: return $default;
123: }
124: }
125: else {
126: return $default;
127: }
128: }
129: return $v;
130: }
131:
132: 133: 134: 135: 136: 137: 138:
139: public function has($name)
140: {
141: return $this->_loose || array_key_exists($name, $this->_vars);
142: }
143:
144: 145: 146: 147: 148: 149:
150: public function keys()
151: {
152: return Pinoco_List::fromArray(array_keys($this->_vars))->sorted();
153: }
154:
155: 156: 157: 158: 159: 160:
161: public function values()
162: {
163: $tmp = $this->_vars;
164: ksort($tmp);
165: return Pinoco_List::fromArray(array_values($tmp));
166: }
167:
168: public function __get($name)
169: {
170: return $this->get($name);
171: }
172:
173: 174: 175: 176: 177: 178: 179:
180: public function set($name, $value)
181: {
182: $this->_vars[$name] = $value;
183: }
184:
185: 186: 187: 188: 189: 190: 191: 192: 193:
194: public function registerAsMethod($name, $callable)
195: {
196: $this->_vars[$name] = new Pinoco_MethodProxy($callable, $this);
197: }
198:
199: 200: 201: 202: 203: 204: 205: 206: 207:
208: public function registerAsDynamic($name, $callable, $context=array())
209: {
210: $this->_vars[$name] = new Pinoco_ValueProxy($callable, $this, false, $context);
211: }
212:
213: 214: 215: 216: 217: 218: 219: 220: 221:
222: public function registerAsLazy($name, $callable, $context=array())
223: {
224: $this->_vars[$name] = new Pinoco_ValueProxy($callable, $this, true, $context);
225: }
226:
227: 228: 229: 230: 231: 232: 233:
234: public function markAsDirty($name)
235: {
236: if (array_key_exists($name, $this->_vars) &&
237: $this->_vars[$name] instanceof Pinoco_ValueProxy
238: ) {
239:
240: $proxy = $this->_vars[$name];
241: $proxy->dirty();
242: }
243: }
244:
245: 246: 247: 248: 249: 250:
251: public function setDefault($value)
252: {
253: $this->_default_val = $value;
254: }
255:
256: 257: 258: 259: 260: 261:
262: public function setLoose($flag)
263: {
264: $this->_loose = $flag;
265: }
266:
267: 268: 269: 270: 271: 272:
273: public function remove($name)
274: {
275: unset($this->_vars[$name]);
276: }
277:
278: public function __set($name, $value)
279: {
280: $this->set($name, $value);
281: }
282:
283: public function __isset($name)
284: {
285: return $this->has($name);
286: }
287:
288: public function __unset($name)
289: {
290: $this->remove($name);
291: }
292:
293: public function __call($name, $arguments)
294: {
295: if ($this->has($name)) {
296: $m = $this->get($name);
297: if ($m instanceof Pinoco_MethodProxy) {
298: return $m->call($arguments);
299: }
300: elseif (is_callable($m)) {
301: return call_user_func_array($m, $arguments);
302: }
303: }
304: throw new BadMethodCallException("The Vars object has no such method: $name.");
305: }
306:
307: 308: 309: 310: 311:
312: public function count()
313: {
314: return count($this->_vars);
315: }
316:
317: public function getIterator()
318: {
319: return new Pinoco_ArrayConvertiblesIterator($this->_vars);
320: }
321:
322: public function offsetSet($offset, $value)
323: {
324: $this->set($offset, $value);
325: }
326:
327: public function offsetExists($offset)
328: {
329: return $this->has($offset);
330: }
331:
332: public function offsetUnset($offset)
333: {
334: $this->remove($offset);
335: }
336:
337: public function offsetGet($offset)
338: {
339: return $this->get($offset);
340: }
341:
342: 343: 344: 345: 346: 347: 348: 349:
350: public function toArray($filter=null, $default=null, $modifier="%s")
351: {
352: $arr = array();
353: $ks = $filter ? $filter : $this->keys();
354: foreach ($ks as $k) {
355: $name = (strpos($modifier, "%") !== false) ? sprintf($modifier, $k) : (
356: is_callable($modifier) ? call_user_func($modifier, $k) : ($modifier . $k)
357: );
358: $arr[$name] = $this->get($k, $default);
359: }
360: return $arr;
361: }
362:
363: 364: 365: 366: 367: 368:
369: public function toArrayRecurse($depth=null)
370: {
371: if ($depth !== null && $depth == 0) { return $this; }
372: $arr = array();
373: foreach ($this->keys() as $k) {
374: $v = $this->get($k);
375: if ($v instanceof Pinoco_ArrayConvertible) {
376: $v = $v->toArrayRecurse($depth !== null ? $depth - 1 : null);
377: }
378: $arr[$k] = $v;
379: }
380: return $arr;
381: }
382:
383: 384: 385: 386: 387: 388: 389: 390: 391: 392:
393: public function import($src, $filter=false, $default=null, $modifier="%s")
394: {
395: if (is_array($src)) {
396: $srcarr = $src;
397: }
398: elseif ($src instanceof Traversable) {
399: $srcarr = array();
400: foreach ($src as $k=>$v) {
401: $srcarr[$k] = $v;
402: }
403: }
404: elseif (is_object($src)) {
405: $srcarr = get_object_vars($src);
406: }
407: else {
408: throw new InvalidArgumentException("Can't import from scalar variable.");
409: }
410: $ks = $filter ? $filter : array_keys($srcarr);
411: foreach ($ks as $k) {
412: $name = (strpos($modifier, "%") !== false) ? sprintf($modifier, $k) : (
413: is_callable($modifier) ? call_user_func($modifier, $k) : ($modifier . $k)
414: );
415: $this->set($name, array_key_exists($k, $srcarr) ? $srcarr[$k] : $default);
416: }
417: }
418:
419: public function __toString() { return __CLASS__; }
420: }
421:
422: