1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13:
14:
15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26: abstract class PresenterComponent extends ComponentContainer implements ISignalReceiver, IStatePersistent, ArrayAccess
27: {
28:
29: protected $params = array();
30:
31:
32:
33: 34:
35: public function __construct(IComponentContainer $parent = NULL, $name = NULL)
36: {
37: $this->monitor('Presenter');
38: parent::__construct($parent, $name);
39: }
40:
41:
42:
43: 44: 45: 46: 47:
48: public function getPresenter($need = TRUE)
49: {
50: return $this->lookup('Presenter', $need);
51: }
52:
53:
54:
55: 56: 57: 58: 59:
60: public function getUniqueId()
61: {
62: return $this->lookupPath('Presenter', TRUE);
63: }
64:
65:
66:
67: 68: 69: 70: 71: 72:
73: protected function attached($presenter)
74: {
75: if ($presenter instanceof Presenter) {
76: $this->loadState($presenter->popGlobalParams($this->getUniqueId()));
77: }
78: }
79:
80:
81:
82: 83: 84: 85: 86: 87:
88: protected function tryCall($method, array $params)
89: {
90: $rc = $this->getReflection();
91: if ($rc->hasMethod($method)) {
92: $rm = $rc->getMethod($method);
93: if ($rm->isPublic() && !$rm->isAbstract() && !$rm->isStatic()) {
94: $rm->invokeNamedArgs($this, $params);
95: return TRUE;
96: }
97: }
98: return FALSE;
99: }
100:
101:
102:
103: 104: 105: 106:
107: public function getReflection()
108: {
109: return new PresenterComponentReflection($this);
110: }
111:
112:
113:
114:
115:
116:
117:
118: 119: 120: 121: 122:
123: public function loadState(array $params)
124: {
125: foreach ($this->getReflection()->getPersistentParams() as $nm => $meta)
126: {
127: if (isset($params[$nm])) { 128: if (isset($meta['def'])) {
129: if (is_array($params[$nm]) && !is_array($meta['def'])) {
130: $params[$nm] = $meta['def']; 131: } else {
132: settype($params[$nm], gettype($meta['def']));
133: }
134: }
135: $this->$nm = & $params[$nm];
136: }
137: }
138: $this->params = $params;
139: }
140:
141:
142:
143: 144: 145: 146: 147: 148:
149: public function saveState(array & $params, $reflection = NULL)
150: {
151: $reflection = $reflection === NULL ? $this->getReflection() : $reflection;
152: foreach ($reflection->getPersistentParams() as $nm => $meta)
153: {
154: if (isset($params[$nm])) {
155: $val = $params[$nm]; 156:
157: } elseif (array_key_exists($nm, $params)) { 158: continue; 159:
160: } elseif (!isset($meta['since']) || $this instanceof $meta['since']) {
161: $val = $this->$nm; 162:
163: } else {
164: continue; 165: }
166:
167: if (is_object($val)) {
168: throw new InvalidStateException("Persistent parameter must be scalar or array, {$this->reflection->name}::\$$nm is " . gettype($val));
169:
170: } else {
171: if (isset($meta['def'])) {
172: settype($val, gettype($meta['def']));
173: if ($val === $meta['def']) $val = NULL;
174: } else {
175: if ((string) $val === '') $val = NULL;
176: }
177: $params[$nm] = $val;
178: }
179: }
180: }
181:
182:
183:
184: 185: 186: 187: 188: 189: 190:
191: final public function getParam($name = NULL, $default = NULL)
192: {
193: if (func_num_args() === 0) {
194: return $this->params;
195:
196: } elseif (isset($this->params[$name])) {
197: return $this->params[$name];
198:
199: } else {
200: return $default;
201: }
202: }
203:
204:
205:
206: 207: 208: 209:
210: final public function getParamId($name)
211: {
212: $uid = $this->getUniqueId();
213: return $uid === '' ? $name : $uid . self::NAME_SEPARATOR . $name;
214: }
215:
216:
217:
218: 219: 220: 221: 222:
223: public static function getPersistentParams()
224: {
225: $rc = new ClassReflection(func_get_arg(0));
226: $params = array();
227: foreach ($rc->getProperties(ReflectionProperty::IS_PUBLIC) as $rp) {
228: if (!$rp->isStatic() && $rp->hasAnnotation('persistent')) {
229: $params[] = $rp->getName();
230: }
231: }
232: return $params;
233: }
234:
235:
236:
237:
238:
239:
240:
241: 242: 243: 244: 245: 246:
247: public function signalReceived($signal)
248: {
249: if (!$this->tryCall($this->formatSignalMethod($signal), $this->params)) {
250: throw new BadSignalException("There is no handler for signal '$signal' in class {$this->reflection->name}.");
251: }
252: }
253:
254:
255:
256: 257: 258: 259: 260:
261: public function formatSignalMethod($signal)
262: {
263: return $signal == NULL ? NULL : 'handle' . $signal; 264: }
265:
266:
267:
268:
269:
270:
271:
272: 273: 274: 275: 276: 277: 278:
279: public function link($destination, $args = array())
280: {
281: if (!is_array($args)) {
282: $args = func_get_args();
283: array_shift($args);
284: }
285:
286: try {
287: return $this->getPresenter()->createRequest($this, $destination, $args, 'link');
288:
289: } catch (InvalidLinkException $e) {
290: return $this->getPresenter()->handleInvalidLink($e);
291: }
292: }
293:
294:
295:
296: 297: 298: 299: 300: 301:
302: public function lazyLink($destination, $args = array())
303: {
304: if (!is_array($args)) {
305: $args = func_get_args();
306: array_shift($args);
307: }
308:
309: return new Link($this, $destination, $args);
310: }
311:
312:
313:
314: 315: 316: 317: 318: 319: 320: 321:
322: public function redirect($code, $destination = NULL, $args = array())
323: {
324: if (!is_numeric($code)) { 325: $args = $destination;
326: $destination = $code;
327: $code = NULL;
328: }
329:
330: if (!is_array($args)) {
331: $args = func_get_args();
332: if (is_numeric(array_shift($args))) array_shift($args);
333: }
334:
335: $presenter = $this->getPresenter();
336: $presenter->redirectUri($presenter->createRequest($this, $destination, $args, 'redirect'), $code);
337: }
338:
339:
340:
341:
342:
343:
344:
345: 346: 347: 348: 349: 350:
351: final public function offsetSet($name, $component)
352: {
353: $this->addComponent($component, $name);
354: }
355:
356:
357:
358: 359: 360: 361: 362: 363:
364: final public function offsetGet($name)
365: {
366: return $this->getComponent($name, TRUE);
367: }
368:
369:
370:
371: 372: 373: 374: 375:
376: final public function offsetExists($name)
377: {
378: return $this->getComponent($name, FALSE) !== NULL;
379: }
380:
381:
382:
383: 384: 385: 386: 387:
388: final public function offsetUnset($name)
389: {
390: $component = $this->getComponent($name, FALSE);
391: if ($component !== NULL) {
392: $this->removeComponent($component);
393: }
394: }
395:
396: }
397: