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