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