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 class {$this->reflection->name}.");
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: 321: 322: 323: 324:
325: public function redirect($code, $destination = NULL, $args = array())
326: {
327: if (!is_numeric($code)) { 328: $args = $destination;
329: $destination = $code;
330: $code = NULL;
331: }
332:
333: if (!is_array($args)) {
334: $args = func_get_args();
335: if (is_numeric(array_shift($args))) array_shift($args);
336: }
337:
338: $presenter = $this->getPresenter();
339: $presenter->redirectUri($presenter->createRequest($this, $destination, $args, 'redirect'), $code);
340: }
341:
342:
343:
344:
345:
346:
347:
348: 349: 350: 351: 352: 353:
354: final public function offsetSet($name, $component)
355: {
356: $this->addComponent($component, $name);
357: }
358:
359:
360:
361: 362: 363: 364: 365: 366:
367: final public function offsetGet($name)
368: {
369: return $this->getComponent($name, TRUE);
370: }
371:
372:
373:
374: 375: 376: 377: 378:
379: final public function offsetExists($name)
380: {
381: return $this->getComponent($name, FALSE) !== NULL;
382: }
383:
384:
385:
386: 387: 388: 389: 390:
391: final public function offsetUnset($name)
392: {
393: $component = $this->getComponent($name, FALSE);
394: if ($component !== NULL) {
395: $this->removeComponent($component);
396: }
397: }
398:
399: }
400: