PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/www/libs/nette-dev/Application/PresenterComponent.php

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