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