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