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: public function __construct(Nette\DI\IContainer $context)
64: {
65: $this->context = $context;
66: }
67:
68:
69:
70: 71: 72: 73:
74: public function run()
75: {
76: $httpRequest = $this->context->httpRequest;
77: $httpResponse = $this->context->httpResponse;
78:
79:
80: if ($this->allowedMethods) {
81: $method = $httpRequest->getMethod();
82: if (!in_array($method, $this->allowedMethods, TRUE)) {
83: $httpResponse->setCode(Nette\Http\IResponse::S501_NOT_IMPLEMENTED);
84: $httpResponse->setHeader('Allow', implode(',', $this->allowedMethods));
85: echo '<h1>Method ' . htmlSpecialChars($method) . ' is not implemented</h1>';
86: return;
87: }
88: }
89:
90:
91: $request = NULL;
92: $repeatedError = FALSE;
93: do {
94: try {
95: if (count($this->requests) > self::$maxLoop) {
96: throw new ApplicationException('Too many loops detected in application life cycle.');
97: }
98:
99: if (!$request) {
100: $this->onStartup($this);
101:
102:
103: $router = $this->getRouter();
104:
105:
106: Diagnostics\RoutingPanel::initialize($this, $httpRequest);
107:
108: $request = $router->match($httpRequest);
109: if (!$request instanceof Request) {
110: $request = NULL;
111: throw new BadRequestException('No route for HTTP request.');
112: }
113:
114: if (strcasecmp($request->getPresenterName(), $this->errorPresenter) === 0) {
115: throw new BadRequestException('Invalid request. Presenter is not achievable.');
116: }
117: }
118:
119: $this->requests[] = $request;
120: $this->onRequest($this, $request);
121:
122:
123: $presenterName = $request->getPresenterName();
124: try {
125: $this->presenter = $this->getPresenterFactory()->createPresenter($presenterName);
126: } catch (InvalidPresenterException $e) {
127: throw new BadRequestException($e->getMessage(), 404, $e);
128: }
129:
130: $this->getPresenterFactory()->getPresenterClass($presenterName);
131: $request->setPresenterName($presenterName);
132: $request->freeze();
133:
134:
135: $response = $this->presenter->run($request);
136: $this->onResponse($this, $response);
137:
138:
139: if ($response instanceof Responses\ForwardResponse) {
140: $request = $response->getRequest();
141: continue;
142:
143: } elseif ($response instanceof IResponse) {
144: $response->send($httpRequest, $httpResponse);
145: }
146: break;
147:
148: } catch (\Exception $e) {
149:
150: $this->onError($this, $e);
151:
152: if (!$this->catchExceptions) {
153: $this->onShutdown($this, $e);
154: throw $e;
155: }
156:
157: if ($repeatedError) {
158: $e = new ApplicationException('An error occurred while executing error-presenter', 0, $e);
159: }
160:
161: if (!$httpResponse->isSent()) {
162: $httpResponse->setCode($e instanceof BadRequestException ? $e->getCode() : 500);
163: }
164:
165: if (!$repeatedError && $this->errorPresenter) {
166: $repeatedError = TRUE;
167: if ($this->presenter instanceof UI\Presenter) {
168: try {
169: $this->presenter->forward(":$this->errorPresenter:", array('exception' => $e));
170: } catch (AbortException $foo) {
171: $request = $this->presenter->getLastCreatedRequest();
172: }
173: } else {
174: $request = new Request(
175: $this->errorPresenter,
176: Request::FORWARD,
177: array('exception' => $e)
178: );
179: }
180:
181:
182: } else {
183: if ($e instanceof BadRequestException) {
184: $code = $e->getCode();
185: } else {
186: $code = 500;
187: Nette\Diagnostics\Debugger::log($e, Nette\Diagnostics\Debugger::ERROR);
188: }
189: require __DIR__ . '/templates/error.phtml';
190: break;
191: }
192: }
193: } while (1);
194:
195: $this->onShutdown($this, isset($e) ? $e : NULL);
196: }
197:
198:
199:
200: 201: 202: 203:
204: final public function getRequests()
205: {
206: return $this->requests;
207: }
208:
209:
210:
211: 212: 213: 214:
215: final public function getPresenter()
216: {
217: return $this->presenter;
218: }
219:
220:
221:
222:
223:
224:
225:
226: 227: 228:
229: protected function getContext()
230: {
231: return $this->context;
232: }
233:
234:
235:
236: 237: 238: 239:
240: public function getRouter()
241: {
242: return $this->context->router;
243: }
244:
245:
246:
247: 248: 249: 250:
251: public function getPresenterFactory()
252: {
253: return $this->context->presenterFactory;
254: }
255:
256:
257:
258:
259:
260:
261:
262: 263: 264: 265: 266:
267: public function storeRequest($expiration = '+ 10 minutes')
268: {
269: $session = $this->context->session->getSection('Nette.Application/requests');
270: do {
271: $key = Nette\Utils\Strings::random(5);
272: } while (isset($session[$key]));
273:
274: $session[$key] = end($this->requests);
275: $session->setExpiration($expiration, $key);
276: return $key;
277: }
278:
279:
280:
281: 282: 283: 284: 285:
286: public function restoreRequest($key)
287: {
288: $session = $this->context->session->getSection('Nette.Application/requests');
289: if (isset($session[$key])) {
290: $request = clone $session[$key];
291: unset($session[$key]);
292: $request->setFlag(Request::RESTORED, TRUE);
293: $this->presenter->sendResponse(new Responses\ForwardResponse($request));
294: }
295: }
296:
297: }
298: