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