PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Nette/Application/PresenterComponent.php

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