Source for file PresenterComponent.php

Documentation is available at PresenterComponent.php

  1. 1: <?php
  2. 2:  
  3. 3: /**
  4. 4:  * Nette Framework
  5. 5:  *
  6. 6:  * Copyright (c) 2004, 2009 David Grudl (http://davidgrudl.com)
  7. 7:  *
  8. 8:  * This source file is subject to the "Nette license" that is bundled
  9. 9:  * with this package in the file license.txt.
  10. 10:  *
  11. 11:  * For more information please see http://nettephp.com
  12. 12:  *
  13. 13:  * @copyright  Copyright (c) 2004, 2009 David Grudl
  14. 14:  * @license    http://nettephp.com/license  Nette license
  15. 15:  * @link       http://nettephp.com
  16. 16:  * @category   Nette
  17. 17:  * @package    Nette\Application
  18. 18:  */
  19. 19:  
  20. 20:  
  21. 21:  
  22. 22: require_once dirname(__FILE__'/../ComponentContainer.php';
  23. 23:  
  24. 24: require_once dirname(__FILE__'/../Application/ISignalReceiver.php';
  25. 25:  
  26. 26: require_once dirname(__FILE__'/../Application/IStatePersistent.php';
  27. 27:  
  28. 28:  
  29. 29:  
  30. 30: /**
  31. 31:  * PresenterComponent is the base class for all presenters components.
  32. 32:  *
  33. 33:  * Components are persistent objects located on a presenter. They have ability to own
  34. 34:  * other child components, and interact with user. Components have properties
  35. 35:  * for storing their status, and responds to user command.
  36. 36:  *
  37. 37:  * @author     David Grudl
  38. 38:  * @copyright  Copyright (c) 2004, 2009 David Grudl
  39. 39:  * @package    Nette\Application
  40. 40:  *
  41. 41:  * @property-read Presenter $presenter 
  42. 42:  */
  43. 44: {
  44. 45:     /** @var array */
  45. 46:     protected $params = array();
  46. 47:  
  47. 48:  
  48. 49:  
  49. 50:     /**
  50. 51:      */
  51. 52:     public function __construct(IComponentContainer $parent NULL$name NULL)
  52. 53:     {
  53. 54:         $this->monitor('Nette\Application\Presenter');
  54. 55:         parent::__construct($parent$name);
  55. 56:     }
  56. 57:  
  57. 58:  
  58. 59:  
  59. 60:     /**
  60. 61:      * Returns the presenter where this component belongs to.
  61. 62:      * @param  bool   throw exception if presenter doesn't exist?
  62. 63:      * @return Presenter|NULL
  63. 64:      */
  64. 65:     public function getPresenter($need TRUE)
  65. 66:     {
  66. 67:         return $this->lookup('Nette\Application\Presenter'$need);
  67. 68:     }
  68. 69:  
  69. 70:  
  70. 71:  
  71. 72:     /**
  72. 73:      * Returns a fully-qualified name that uniquely identifies the component
  73. 74:      * within the presenter hierarchy.
  74. 75:      * @return string 
  75. 76:      */
  76. 77:     public function getUniqueId()
  77. 78:     {
  78. 79:         return $this->lookupPath('Nette\Application\Presenter'TRUE);
  79. 80:     }
  80. 81:  
  81. 82:  
  82. 83:  
  83. 84:     /**
  84. 85:      * This method will be called when the component (or component's parent)
  85. 86:      * becomes attached to a monitored object. Do not call this method yourself.
  86. 87:      * @param  IComponent 
  87. 88:      * @return void 
  88. 89:      */
  89. 90:     protected function attached($presenter)
  90. 91:     {
  91. 92:         if ($presenter instanceof Presenter{
  92. 93:             $this->loadState($presenter->popGlobalParams($this->getUniqueId()));
  93. 94:         }
  94. 95:     }
  95. 96:  
  96. 97:  
  97. 98:  
  98. 99:     /**
  99. 100:      * Calls public method if exists.
  100. 101:      * @param  string 
  101. 102:      * @param  array 
  102. 103:      * @return bool  does method exist?
  103. 104:      */
  104. 105:     protected function tryCall($methodarray $params)
  105. 106:     {
  106. 107:         $class $this->getClass();
  107. 108:         if (PresenterHelpers::isMethodCallable($class$method)) {
  108. 109:             $args PresenterHelpers::paramsToArgs($class$method$params);
  109. 110:             call_user_func_array(array($this$method)$args);
  110. 111:             return TRUE;
  111. 112:         }
  112. 113:         return FALSE;
  113. 114:     }
  114. 115:  
  115. 116:  
  116. 117:  
  117. 118:     /********************* interface IStatePersistent ****************d*g**/
  118. 119:  
  119. 120:  
  120. 121:  
  121. 122:     /**
  122. 123:      * Loads state informations.
  123. 124:      * @param  array 
  124. 125:      * @return void 
  125. 126:      */
  126. 127:     public function loadState(array $params)
  127. 128:     {
  128. 129:         foreach (PresenterHelpers::getPersistentParams($this->getClass()) as $nm => $meta)
  129. 130:         {
  130. 131:             if (isset($params[$nm])) // ignore NULL values
  131. 132:                 if (isset($meta['def'])) {
  132. 133:                     settype($params[$nm]gettype($meta['def']));
  133. 134:                 }
  134. 135:                 $this->$nm $params[$nm];
  135. 136:             }
  136. 137:         }
  137. 138:         $this->params $params;
  138. 139:     }
  139. 140:  
  140. 141:  
  141. 142:  
  142. 143:     /**
  143. 144:      * Saves state informations for next request.
  144. 145:      * @param  array 
  145. 146:      * @param  portion specified by class name (used by Presenter)
  146. 147:      * @return void 
  147. 148:      */
  148. 149:     public function saveState(array $params$forClass NULL)
  149. 150:     {
  150. 151:         foreach (PresenterHelpers::getPersistentParams($forClass === NULL $this->getClass($forClassas $nm => $meta)
  151. 152:         {
  152. 153:             if (isset($params[$nm])) {
  153. 154:                 $val $params[$nm]// injected value
  154. 155:  
  155. 156:             elseif (array_key_exists($nm$params)) // $params[$nm] === NULL
  156. 157:                 continue// means skip
  157. 158:  
  158. 159:             elseif (!isset($meta['since']|| $this instanceof $meta['since']{
  159. 160:                 $val $this->$nm// object property value
  160. 161:  
  161. 162:             else {
  162. 163:                 continue// ignored parameter
  163. 164:             }
  164. 165:  
  165. 166:             if (is_object($val)) {
  166. 167:                 throw new InvalidStateException("Persistent parameter must be scalar or array, '$this->class::\$$nm' is gettype($val));
  167. 168:  
  168. 169:             else {
  169. 170:                 if (isset($meta['def'])) {
  170. 171:                     settype($valgettype($meta['def']));
  171. 172:                     if ($val === $meta['def']$val NULL;
  172. 173:                 else {
  173. 174:                     if ((string) $val === ''$val NULL;
  174. 175:                 }
  175. 176:                 $params[$nm$val;
  176. 177:             }
  177. 178:         }
  178. 179:     }
  179. 180:  
  180. 181:  
  181. 182:  
  182. 183:     /**
  183. 184:      * Returns component param.
  184. 185:      * If no key is passed, returns the entire array.
  185. 186:      * @param  string key
  186. 187:      * @param  mixed  default value
  187. 188:      * @return mixed 
  188. 189:      */
  189. 190:     final public function getParam($name NULL$default NULL)
  190. 191:     {
  191. 192:         if (func_num_args(=== 0{
  192. 193:             return $this->params;
  193. 194:  
  194. 195:         elseif (isset($this->params[$name])) {
  195. 196:             return $this->params[$name];
  196. 197:  
  197. 198:         else {
  198. 199:             return $default;
  199. 200:         }
  200. 201:     }
  201. 202:  
  202. 203:  
  203. 204:  
  204. 205:     /**
  205. 206:      * Returns a fully-qualified name that uniquely identifies the parameter.
  206. 207:      * @return string 
  207. 208:      */
  208. 209:     final public function getParamId($name)
  209. 210:     {
  210. 211:         $uid $this->getUniqueId();
  211. 212:         return $uid === '' $name $uid self::NAME_SEPARATOR $name;
  212. 213:     }
  213. 214:  
  214. 215:  
  215. 216:  
  216. 217:     /**
  217. 218:      * Returns array of classes persistent parameters. They have public visibility and are non-static.
  218. 219:      * This default implementation detects persistent parameters by annotation @persistent.
  219. 220:      * @return array 
  220. 221:      */
  221. 222:     public static function getPersistentParams()
  222. 223:     {
  223. 224:         $rc new ReflectionClass(func_get_arg(0));
  224. 225:         $params array();
  225. 226:         foreach ($rc->getProperties(as $rp{
  226. 227:             if ($rp->isPublic(&& !$rp->isStatic(&& Annotations::get($rp'persistent')) {
  227. 228:                 $params[$rp->getName();
  228. 229:             }
  229. 230:         }
  230. 231:         return $params;
  231. 232:     }
  232. 233:  
  233. 234:  
  234. 235:  
  235. 236:     /********************* interface ISignalReceiver ****************d*g**/
  236. 237:  
  237. 238:  
  238. 239:  
  239. 240:     /**
  240. 241:      * Calls signal handler method.
  241. 242:      * @param  string 
  242. 243:      * @return void 
  243. 244:      * @throws BadSignalException if there is not handler method
  244. 245:      */
  245. 246:     public function signalReceived($signal)
  246. 247:     {
  247. 248:         if (!$this->tryCall($this->formatSignalMethod($signal)$this->params)) {
  248. 249:             throw new BadSignalException("There is no handler for signal '$signal' in '{$this->getClass()}' class.");
  249. 250:         }
  250. 251:     }
  251. 252:  
  252. 253:  
  253. 254:  
  254. 255:     /**
  255. 256:      * Formats signal handler method name -> case sensitivity doesn't matter.
  256. 257:      * @param  string 
  257. 258:      * @return string 
  258. 259:      */
  259. 260:     public function formatSignalMethod($signal)
  260. 261:     {
  261. 262:         return $signal == NULL NULL 'handle' $signal// intentionally ==
  262. 263:     }
  263. 264:  
  264. 265:  
  265. 266:  
  266. 267:     /********************* navigation ****************d*g**/
  267. 268:  
  268. 269:  
  269. 270:  
  270. 271:     /**
  271. 272:      * Generates URL to presenter, action or signal.
  272. 273:      * @param  string   destination in format "[[module:]presenter:]action" or "signal!"
  273. 274:      * @param  array|mixed
  274. 275:      * @return string 
  275. 276:      * @throws InvalidLinkException
  276. 277:      */
  277. 278:     public function link($destination$args array())
  278. 279:     {
  279. 280:         if (!is_array($args)) {
  280. 281:             $args func_get_args();
  281. 282:             array_shift($args);
  282. 283:         }
  283. 284:  
  284. 285:         try {
  285. 286:             return $this->getPresenter()->createRequest($this$destination$args'link');
  286. 287:  
  287. 288:         catch (InvalidLinkException $e{
  288. 289:             return $this->getPresenter()->handleInvalidLink($e);
  289. 290:         }
  290. 291:     }
  291. 292:  
  292. 293:  
  293. 294:  
  294. 295:     /**
  295. 296:      * Returns destination as Link object.
  296. 297:      * @param  string   destination in format "[[module:]presenter:]view" or "signal!"
  297. 298:      * @param  array|mixed
  298. 299:      * @return Link 
  299. 300:      */
  300. 301:     public function lazyLink($destination$args array())
  301. 302:     {
  302. 303:         if (!is_array($args)) {
  303. 304:             $args func_get_args();
  304. 305:             array_shift($args);
  305. 306:         }
  306. 307:  
  307. 308:         return new Link($this$destination$args);
  308. 309:     }
  309. 310:  
  310. 311:  
  311. 312:  
  312. 313:     /**
  313. 314:      * @deprecated
  314. 315:      */
  315. 316:     public function ajaxLink($destination$args array())
  316. 317:     {
  317. 318:         throw new DeprecatedException(__METHOD__ . '() is deprecated.');
  318. 319:     }
  319. 320:  
  320. 321:  
  321. 322:  
  322. 323:     /**
  323. 324:      * Redirect to another presenter, action or signal.
  324. 325:      * @param  int      [optional] HTTP error code
  325. 326:      * @param  string   destination in format "[[module:]presenter:]view" or "signal!"
  326. 327:      * @param  array|mixed
  327. 328:      * @return void 
  328. 329:      * @throws RedirectingException
  329. 330:      */
  330. 331:     public function redirect($code$destination NULL$args array())
  331. 332:     {
  332. 333:         if (!is_numeric($code)) // first parameter is optional
  333. 334:             $args $destination;
  334. 335:             $destination $code;
  335. 336:             $code NULL;
  336. 337:         }
  337. 338:  
  338. 339:         if (!is_array($args)) {
  339. 340:             $args func_get_args();
  340. 341:             if (is_numeric(array_shift($args))) array_shift($args);
  341. 342:         }
  342. 343:  
  343. 344:         $presenter $this->getPresenter();
  344. 345:         $presenter->redirectUri($presenter->createRequest($this$destination$args'redirect')$code);
  345. 346:     }
  346. 347: