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: