PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/Nette/Application/Application.php

https://github.com/DocX/nette
PHP | 385 lines | 189 code | 93 blank | 103 comment | 24 complexity | e08aeb9ae5260c06625270e738a4178f 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. /*use Nette\Environment;*/
  20. require_once dirname(__FILE__) . '/../Object.php';
  21. /**
  22. * Front Controller.
  23. *
  24. * @author David Grudl
  25. * @copyright Copyright (c) 2004, 2009 David Grudl
  26. * @package Nette\Application
  27. */
  28. class Application extends /*Nette\*/Object
  29. {
  30. /** @var int */
  31. public static $maxLoop = 20;
  32. /** @var array */
  33. public $defaultServices = array(
  34. 'Nette\Application\IRouter' => 'Nette\Application\MultiRouter',
  35. 'Nette\Application\IPresenterLoader' => 'Nette\Application\PresenterLoader',
  36. );
  37. /** @var bool enable fault barrier? */
  38. public $catchExceptions;
  39. /** @var string */
  40. public $errorPresenter;
  41. /** @var array of function(Application $sender); Occurs before the application loads presenter */
  42. public $onStartup;
  43. /** @var array of function(Application $sender, \Exception $e = NULL); Occurs before the application shuts down */
  44. public $onShutdown;
  45. /** @var array of function(Application $sender, PresenterRequest $request); Occurs when a new request is ready for dispatch */
  46. public $onRequest;
  47. /** @var array of function(Application $sender, \Exception $e); Occurs when an unhandled exception occurs in the application */
  48. public $onError;
  49. /** @var array of string */
  50. public $allowedMethods = array('GET', 'POST', 'HEAD', 'PUT', 'DELETE');
  51. /** @var array of PresenterRequest */
  52. private $requests = array();
  53. /** @var Presenter */
  54. private $presenter;
  55. /** @var Nette\ServiceLocator */
  56. private $serviceLocator;
  57. /**
  58. * Dispatch a HTTP request to a front controller.
  59. * @return void
  60. */
  61. public function run()
  62. {
  63. $httpRequest = $this->getHttpRequest();
  64. $httpResponse = $this->getHttpResponse();
  65. $httpRequest->setEncoding('UTF-8');
  66. $httpResponse->setHeader('X-Powered-By', 'Nette Framework');
  67. if (Environment::getVariable('baseUri') === NULL) {
  68. Environment::setVariable('baseUri', $httpRequest->getUri()->getBasePath());
  69. }
  70. // check HTTP method
  71. if ($this->allowedMethods) {
  72. $method = $httpRequest->getMethod();
  73. if (!in_array($method, $this->allowedMethods, TRUE)) {
  74. $httpResponse->setCode(/*Nette\Web\*/IHttpResponse::S501_NOT_IMPLEMENTED);
  75. $httpResponse->setHeader('Allow', implode(',', $this->allowedMethods));
  76. $method = htmlSpecialChars($method);
  77. echo "<h1>Method $method is not implemented</h1>";
  78. return;
  79. }
  80. }
  81. // dispatching
  82. $request = NULL;
  83. $repeatedError = FALSE;
  84. do {
  85. try {
  86. if (count($this->requests) > self::$maxLoop) {
  87. throw new ApplicationException('Too many loops detected in application life cycle.');
  88. }
  89. if (!$request) {
  90. $this->onStartup($this);
  91. // default router
  92. $router = $this->getRouter();
  93. if ($router instanceof MultiRouter && !count($router)) {
  94. $router[] = new SimpleRouter(array(
  95. 'presenter' => 'Default',
  96. 'action' => 'default',
  97. ));
  98. }
  99. // routing
  100. $request = $router->match($httpRequest);
  101. if (!($request instanceof PresenterRequest)) {
  102. $request = NULL;
  103. throw new BadRequestException('No route for HTTP request.');
  104. }
  105. if (strcasecmp($request->getPresenterName(), $this->errorPresenter) === 0) {
  106. throw new BadRequestException('Invalid request.');
  107. }
  108. }
  109. $this->requests[] = $request;
  110. $this->onRequest($this, $request);
  111. // Instantiate presenter
  112. $presenter = $request->getPresenterName();
  113. try {
  114. $class = $this->getPresenterLoader()->getPresenterClass($presenter);
  115. $request->setPresenterName($presenter);
  116. } catch (InvalidPresenterException $e) {
  117. throw new BadRequestException($e->getMessage(), 404, $e);
  118. }
  119. $request->freeze();
  120. // Execute presenter
  121. $this->presenter = new $class;
  122. $response = $this->presenter->run($request);
  123. // Send response
  124. if ($response instanceof ForwardingResponse) {
  125. $request = $response->getRequest();
  126. continue;
  127. } elseif ($response instanceof IPresenterResponse) {
  128. $response->send();
  129. }
  130. break;
  131. } catch (/*\*/Exception $e) {
  132. // fault barrier
  133. if ($this->catchExceptions === NULL) {
  134. $this->catchExceptions = Environment::isProduction();
  135. }
  136. if (!$this->catchExceptions) {
  137. throw $e;
  138. }
  139. $this->onError($this, $e);
  140. if ($repeatedError) {
  141. $e = new ApplicationException('An error occured while executing error-presenter', 0, $e);
  142. }
  143. if (!$httpResponse->isSent()) {
  144. $httpResponse->setCode($e instanceof BadRequestException ? $e->getCode() : 500);
  145. }
  146. if (!$repeatedError && $this->errorPresenter) {
  147. $repeatedError = TRUE;
  148. $request = new PresenterRequest(
  149. $this->errorPresenter,
  150. PresenterRequest::FORWARD,
  151. array('exception' => $e)
  152. );
  153. // continue
  154. } else { // default error handler
  155. echo "<meta name='robots' content='noindex'>\n\n";
  156. if ($e instanceof BadRequestException) {
  157. echo "<title>404 Not Found</title>\n\n<h1>Not Found</h1>\n\n<p>The requested URL was not found on this server.</p>";
  158. } else {
  159. /*Nette\*/Debug::processException($e, FALSE);
  160. echo "<title>500 Internal Server Error</title>\n\n<h1>Server Error</h1>\n\n",
  161. "<p>The server encountered an internal error and was unable to complete your request. Please try again later.</p>";
  162. }
  163. echo "\n\n<hr>\n<small><i>Nette Framework</i></small>";
  164. break;
  165. }
  166. }
  167. } while (1);
  168. $this->onShutdown($this, isset($e) ? $e : NULL);
  169. }
  170. /**
  171. * Returns all processed requests.
  172. * @return array of PresenterRequest
  173. */
  174. final public function getRequests()
  175. {
  176. return $this->requests;
  177. }
  178. /**
  179. * Returns current presenter.
  180. * @return Presenter
  181. */
  182. final public function getPresenter()
  183. {
  184. return $this->presenter;
  185. }
  186. /********************* services ****************d*g**/
  187. /**
  188. * Gets the service locator (experimental).
  189. * @return Nette\IServiceLocator
  190. */
  191. final public function getServiceLocator()
  192. {
  193. if ($this->serviceLocator === NULL) {
  194. $this->serviceLocator = new /*Nette\*/ServiceLocator(Environment::getServiceLocator());
  195. foreach ($this->defaultServices as $name => $service) {
  196. if (!$this->serviceLocator->hasService($name)) {
  197. $this->serviceLocator->addService($name, $service);
  198. }
  199. }
  200. }
  201. return $this->serviceLocator;
  202. }
  203. /**
  204. * Gets the service object of the specified type.
  205. * @param string service name
  206. * @param array options in case service is not singleton
  207. * @return object
  208. */
  209. final public function getService($name, array $options = NULL)
  210. {
  211. return $this->getServiceLocator()->getService($name, $options);
  212. }
  213. /**
  214. * Returns router.
  215. * @return IRouter
  216. */
  217. public function getRouter()
  218. {
  219. return $this->getServiceLocator()->getService('Nette\Application\IRouter');
  220. }
  221. /**
  222. * Changes router.
  223. * @param IRouter
  224. * @return Application provides a fluent interface
  225. */
  226. public function setRouter(IRouter $router)
  227. {
  228. $this->getServiceLocator()->addService('Nette\Application\IRouter', $router);
  229. return $this;
  230. }
  231. /**
  232. * Returns presenter loader.
  233. * @return IPresenterLoader
  234. */
  235. public function getPresenterLoader()
  236. {
  237. return $this->getServiceLocator()->getService('Nette\Application\IPresenterLoader');
  238. }
  239. /********************* request serialization ****************d*g**/
  240. /**
  241. * Stores current request to session.
  242. * @param mixed optional expiration time
  243. * @return string key
  244. */
  245. public function storeRequest($expiration = '+ 10 minutes')
  246. {
  247. $session = $this->getSession()->getNamespace('Nette.Application/requests');
  248. do {
  249. $key = substr(md5(lcg_value()), 0, 4);
  250. } while (isset($session[$key]));
  251. $session[$key] = end($this->requests);
  252. $session->setExpiration($expiration, $key);
  253. return $key;
  254. }
  255. /**
  256. * Restores current request to session.
  257. * @param string key
  258. * @return void
  259. */
  260. public function restoreRequest($key)
  261. {
  262. $session = $this->getSession()->getNamespace('Nette.Application/requests');
  263. if (isset($session[$key])) {
  264. $request = clone $session[$key];
  265. unset($session[$key]);
  266. $request->setFlag(PresenterRequest::RESTORED, TRUE);
  267. $this->presenter->terminate(new ForwardingResponse($request));
  268. }
  269. }
  270. /********************* backend ****************d*g**/
  271. /**
  272. * @return Nette\Web\IHttpRequest
  273. */
  274. protected function getHttpRequest()
  275. {
  276. return Environment::getHttpRequest();
  277. }
  278. /**
  279. * @return Nette\Web\IHttpResponse
  280. */
  281. protected function getHttpResponse()
  282. {
  283. return Environment::getHttpResponse();
  284. }
  285. /**
  286. * @return Nette\Web\Session
  287. */
  288. protected function getSession()
  289. {
  290. return Environment::getSession();
  291. }
  292. }