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