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