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