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: {
130: if (isset($params[$nm])) {
131: if (isset($meta['def'])) {
132: if (is_array($params[$nm]) && !is_array($meta['def'])) {
133: $params[$nm] = $meta['def'];
134: } else {
135: settype($params[$nm], gettype($meta['def']));
136: }
137: }
138: $this->$nm = & $params[$nm];
139: }
140: }
141: $this->params = $params;
142: }
143:
144:
145:
146: 147: 148: 149: 150: 151:
152: public function saveState(array & $params, $reflection = NULL)
153: {
154: $reflection = $reflection === NULL ? $this->getReflection() : $reflection;
155: foreach ($reflection->getPersistentParams() as $nm => $meta)
156: {
157: if (isset($params[$nm])) {
158: $val = $params[$nm];
159:
160: } elseif (array_key_exists($nm, $params)) {
161: continue;
162:
163: } elseif (!isset($meta['since']) || $this instanceof $meta['since']) {
164: $val = $this->$nm;
165:
166: } else {
167: continue;
168: }
169:
170: if (is_object($val)) {
171: throw new \InvalidStateException("Persistent parameter must be scalar or array, {$this->reflection->name}::\$$nm is " . gettype($val));
172:
173: } else {
174: if (isset($meta['def'])) {
175: settype($val, gettype($meta['def']));
176: if ($val === $meta['def']) $val = NULL;
177: } else {
178: if ((string) $val === '') $val = NULL;
179: }
180: $params[$nm] = $val;
181: }
182: }
183: }
184:
185:
186:
187: 188: 189: 190: 191: 192: 193:
194: final public function getParam($name = NULL, $default = NULL)
195: {
196: if (func_num_args() === 0) {
197: return $this->params;
198:
199: } elseif (isset($this->params[$name])) {
200: return $this->params[$name];
201:
202: } else {
203: return $default;
204: }
205: }
206:
207:
208:
209: 210: 211: 212:
213: final public function getParamId($name)
214: {
215: $uid = $this->getUniqueId();
216: return $uid === '' ? $name : $uid . self::NAME_SEPARATOR . $name;
217: }
218:
219:
220:
221: 222: 223: 224: 225:
226: public static function getPersistentParams()
227: {
228: $rc = new Nette\Reflection\ClassReflection(get_called_class());
229: $params = array();
230: foreach ($rc->getProperties(\ReflectionProperty::IS_PUBLIC) as $rp) {
231: if (!$rp->isStatic() && $rp->hasAnnotation('persistent')) {
232: $params[] = $rp->getName();
233: }
234: }
235: return $params;
236: }
237:
238:
239:
240:
241:
242:
243:
244: 245: 246: 247: 248: 249:
250: public function signalReceived($signal)
251: {
252: if (!$this->tryCall($this->formatSignalMethod($signal), $this->params)) {
253: throw new BadSignalException("There is no handler for signal '$signal' in {$this->reflection->name} class.");
254: }
255: }
256:
257:
258:
259: 260: 261: 262: 263:
264: public function formatSignalMethod($signal)
265: {
266: return $signal == NULL ? NULL : 'handle' . $signal;
267: }
268:
269:
270:
271:
272:
273:
274:
275: 276: 277: 278: 279: 280: 281:
282: public function link($destination, $args = array())
283: {
284: if (!is_array($args)) {
285: $args = func_get_args();
286: array_shift($args);
287: }
288:
289: try {
290: return $this->getPresenter()->createRequest($this, $destination, $args, 'link');
291:
292: } catch (InvalidLinkException $e) {
293: return $this->getPresenter()->handleInvalidLink($e);
294: }
295: }
296:
297:
298:
299: 300: 301: 302: 303: 304:
305: public function lazyLink($destination, $args = array())
306: {
307: if (!is_array($args)) {
308: $args = func_get_args();
309: array_shift($args);
310: }
311:
312: return new Link($this, $destination, $args);
313: }
314:
315:
316:
317: 318: 319:
320: public function ajaxLink($destination, $args = array())
321: {
322: throw new \DeprecatedException(__METHOD__ . '() is deprecated.');
323: }
324:
325:
326:
327: 328: 329: 330: 331: 332: 333: 334:
335: public function redirect($code, $destination = NULL, $args = array())
336: {
337: if (!is_numeric($code)) {
338: $args = $destination;
339: $destination = $code;
340: $code = NULL;
341: }
342:
343: if (!is_array($args)) {
344: $args = func_get_args();
345: if (is_numeric(array_shift($args))) array_shift($args);
346: }
347:
348: $presenter = $this->getPresenter();
349: $presenter->redirectUri($presenter->createRequest($this, $destination, $args, 'redirect'), $code);
350: }
351:
352:
353:
354:
355:
356:
357:
358: 359: 360: 361: 362: 363:
364: final public function offsetSet($name, $component)
365: {
366: $this->addComponent($component, $name);
367: }
368:
369:
370:
371: 372: 373: 374: 375: 376:
377: final public function offsetGet($name)
378: {
379: return $this->getComponent($name, TRUE);
380: }
381:
382:
383:
384: 385: 386: 387: 388:
389: final public function offsetExists($name)
390: {
391: return $this->getComponent($name, FALSE) !== NULL;
392: }
393:
394:
395:
396: 397: 398: 399: 400:
401: final public function offsetUnset($name)
402: {
403: $component = $this->getComponent($name, FALSE);
404: if ($component !== NULL) {
405: $this->removeComponent($component);
406: }
407: }
408:
409: }
410: