1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Nette\Application;
13:
14: use Nette,
15: Nette\Environment;
16:
17:
18:
19: 20: 21: 22: 23:
24: class Application extends Nette\Object
25: {
26:
27: public static $maxLoop = 20;
28:
29:
30: public $defaultServices = array(
31: 'Nette\\Application\\IRouter' => 'Nette\Application\MultiRouter',
32: 'Nette\\Application\\IPresenterLoader' => array(__CLASS__, 'createPresenterLoader'),
33: );
34:
35:
36: public $catchExceptions;
37:
38:
39: public $errorPresenter;
40:
41:
42: public $onStartup;
43:
44:
45: public $onShutdown;
46:
47:
48: public $onRequest;
49:
50:
51: public $onError;
52:
53:
54: public $allowedMethods = array('GET', 'POST', 'HEAD', 'PUT', 'DELETE');
55:
56:
57: private $requests = array();
58:
59:
60: private $presenter;
61:
62:
63: private $serviceLocator;
64:
65:
66:
67: 68: 69: 70:
71: public function run()
72: {
73: $httpRequest = $this->getHttpRequest();
74: $httpResponse = $this->getHttpResponse();
75:
76: $httpRequest->setEncoding('UTF-8');
77: $httpResponse->setHeader('X-Powered-By', 'Nette Framework');
78:
79: if (Environment::getVariable('baseUri') === NULL) {
80: Environment::setVariable('baseUri', $httpRequest->getUri()->getBasePath());
81: }
82:
83:
84: $session = $this->getSession();
85: if (!$session->isStarted() && $session->exists()) {
86: $session->start();
87: }
88:
89:
90: if ($this->allowedMethods) {
91: $method = $httpRequest->getMethod();
92: if (!in_array($method, $this->allowedMethods, TRUE)) {
93: $httpResponse->setCode(Nette\Web\IHttpResponse::S501_NOT_IMPLEMENTED);
94: $httpResponse->setHeader('Allow', implode(',', $this->allowedMethods));
95: echo '<h1>Method ' . htmlSpecialChars($method) . ' is not implemented</h1>';
96: return;
97: }
98: }
99:
100:
101: $request = NULL;
102: $repeatedError = FALSE;
103: do {
104: try {
105: if (count($this->requests) > self::$maxLoop) {
106: throw new ApplicationException('Too many loops detected in application life cycle.');
107: }
108:
109: if (!$request) {
110: $this->onStartup($this);
111:
112:
113: $router = $this->getRouter();
114: if ($router instanceof MultiRouter && !count($router)) {
115: $router[] = new SimpleRouter(array(
116: 'presenter' => 'Default',
117: 'action' => 'default',
118: ));
119: }
120:
121:
122: $request = $router->match($httpRequest);
123: if (!($request instanceof PresenterRequest)) {
124: $request = NULL;
125: throw new BadRequestException('No route for HTTP request.');
126: }
127:
128: if (strcasecmp($request->getPresenterName(), $this->errorPresenter) === 0) {
129: throw new BadRequestException('Invalid request.');
130: }
131: }
132:
133: $this->requests[] = $request;
134: $this->onRequest($this, $request);
135:
136:
137: $presenter = $request->getPresenterName();
138: try {
139: $class = $this->getPresenterLoader()->getPresenterClass($presenter);
140: $request->setPresenterName($presenter);
141: } catch (InvalidPresenterException $e) {
142: throw new BadRequestException($e->getMessage(), 404, $e);
143: }
144: $request->freeze();
145:
146:
147: $this->presenter = new $class;
148: $response = $this->presenter->run($request);
149:
150:
151: if ($response instanceof ForwardingResponse) {
152: $request = $response->getRequest();
153: continue;
154:
155: } elseif ($response instanceof IPresenterResponse) {
156: $response->send();
157: }
158: break;
159:
160: } catch (\Exception $e) {
161:
162: if ($this->catchExceptions === NULL) {
163: $this->catchExceptions = Environment::isProduction();
164: }
165:
166: $this->onError($this, $e);
167:
168: if (!$this->catchExceptions) {
169: $this->onShutdown($this, $e);
170: throw $e;
171: }
172:
173: if ($repeatedError) {
174: $e = new ApplicationException('An error occured while executing error-presenter', 0, $e);
175: }
176:
177: if (!$httpResponse->isSent()) {
178: $httpResponse->setCode($e instanceof BadRequestException ? $e->getCode() : 500);
179: }
180:
181: if (!$repeatedError && $this->errorPresenter) {
182: $repeatedError = TRUE;
183: $request = new PresenterRequest(
184: $this->errorPresenter,
185: PresenterRequest::FORWARD,
186: array('exception' => $e)
187: );
188:
189:
190: } else {
191: echo "<meta name='robots' content='noindex'>\n\n";
192: if ($e instanceof BadRequestException) {
193: 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>";
194:
195: } else {
196: Nette\Debug::processException($e, FALSE);
197: echo "<title>500 Internal Server Error</title>\n\n<h1>Server Error</h1>\n\n",
198: "<p>The server encountered an internal error and was unable to complete your request. Please try again later.</p>";
199: }
200: echo "\n\n<hr>\n<small><i>Nette Framework</i></small>";
201: break;
202: }
203: }
204: } while (1);
205:
206: $this->onShutdown($this, isset($e) ? $e : NULL);
207: }
208:
209:
210:
211: 212: 213: 214:
215: final public function getRequests()
216: {
217: return $this->requests;
218: }
219:
220:
221:
222: 223: 224: 225:
226: final public function getPresenter()
227: {
228: return $this->presenter;
229: }
230:
231:
232:
233:
234:
235:
236:
237: 238: 239: 240:
241: final public function getServiceLocator()
242: {
243: if ($this->serviceLocator === NULL) {
244: $this->serviceLocator = new Nette\ServiceLocator(Environment::getServiceLocator());
245:
246: foreach ($this->defaultServices as $name => $service) {
247: if (!$this->serviceLocator->hasService($name)) {
248: $this->serviceLocator->addService($name, $service);
249: }
250: }
251: }
252: return $this->serviceLocator;
253: }
254:
255:
256:
257: 258: 259: 260: 261: 262:
263: final public function getService($name, array $options = NULL)
264: {
265: return $this->getServiceLocator()->getService($name, $options);
266: }
267:
268:
269:
270: 271: 272: 273:
274: public function getRouter()
275: {
276: return $this->getServiceLocator()->getService('Nette\\Application\\IRouter');
277: }
278:
279:
280:
281: 282: 283: 284: 285:
286: public function setRouter(IRouter $router)
287: {
288: $this->getServiceLocator()->addService('Nette\\Application\\IRouter', $router);
289: return $this;
290: }
291:
292:
293:
294: 295: 296: 297:
298: public function getPresenterLoader()
299: {
300: return $this->getServiceLocator()->getService('Nette\\Application\\IPresenterLoader');
301: }
302:
303:
304:
305:
306:
307:
308:
309: 310: 311:
312: public static function createPresenterLoader()
313: {
314: return new PresenterLoader(Environment::getVariable('appDir'));
315: }
316:
317:
318:
319:
320:
321:
322:
323: 324: 325: 326: 327:
328: public function storeRequest($expiration = '+ 10 minutes')
329: {
330: $session = $this->getSession('Nette.Application/requests');
331: do {
332: $key = substr(md5(lcg_value()), 0, 4);
333: } while (isset($session[$key]));
334:
335: $session[$key] = end($this->requests);
336: $session->setExpiration($expiration, $key);
337: return $key;
338: }
339:
340:
341:
342: 343: 344: 345: 346:
347: public function restoreRequest($key)
348: {
349: $session = $this->getSession('Nette.Application/requests');
350: if (isset($session[$key])) {
351: $request = clone $session[$key];
352: unset($session[$key]);
353: $request->setFlag(PresenterRequest::RESTORED, TRUE);
354: $this->presenter->terminate(new ForwardingResponse($request));
355: }
356: }
357:
358:
359:
360:
361:
362:
363:
364: 365: 366:
367: protected function getHttpRequest()
368: {
369: return Environment::getHttpRequest();
370: }
371:
372:
373:
374: 375: 376:
377: protected function getHttpResponse()
378: {
379: return Environment::getHttpResponse();
380: }
381:
382:
383:
384: 385: 386:
387: protected function getSession($namespace = NULL)
388: {
389: return Environment::getSession($namespace);
390: }
391:
392: }
393: