PageRenderTime 40ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/Nette/Application/PresenterComponent.php

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