PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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

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