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