1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13:
14:
15: 16: 17: 18: 19: 20:
21: class NApplication extends NObject
22: {
23:
24: public static $maxLoop = 20;
25:
26:
27: public $catchExceptions;
28:
29:
30: public $errorPresenter;
31:
32:
33: public $onStartup;
34:
35:
36: public $onShutdown;
37:
38:
39: public $onRequest;
40:
41:
42: public $onResponse;
43:
44:
45: public $onError;
46:
47:
48: public $allowedMethods = array('GET', 'POST', 'HEAD', 'PUT', 'DELETE');
49:
50:
51: private $requests = array();
52:
53:
54: private $presenter;
55:
56:
57: private $context;
58:
59:
60:
61: public function __construct(IDIContainer $context)
62: {
63: $this->context = $context;
64: }
65:
66:
67:
68: 69: 70: 71:
72: public function run()
73: {
74: $httpRequest = $this->context->httpRequest;
75: $httpResponse = $this->context->httpResponse;
76:
77:
78: if ($this->allowedMethods) {
79: $method = $httpRequest->getMethod();
80: if (!in_array($method, $this->allowedMethods, TRUE)) {
81: $httpResponse->setCode(IHttpResponse::S501_NOT_IMPLEMENTED);
82: $httpResponse->setHeader('Allow', implode(',', $this->allowedMethods));
83: echo '<h1>Method ' . htmlSpecialChars($method) . ' is not implemented</h1>';
84: return;
85: }
86: }
87:
88:
89: $request = NULL;
90: $repeatedError = FALSE;
91: do {
92: try {
93: if (count($this->requests) > self::$maxLoop) {
94: throw new NApplicationException('Too many loops detected in application life cycle.');
95: }
96:
97: if (!$request) {
98: $this->onStartup($this);
99:
100:
101: $router = $this->getRouter();
102:
103:
104: NRoutingDebugger::initialize($this, $httpRequest);
105:
106: $request = $router->match($httpRequest);
107: if (!$request instanceof NPresenterRequest) {
108: $request = NULL;
109: throw new NBadRequestException('No route for HTTP request.');
110: }
111:
112: if (strcasecmp($request->getPresenterName(), $this->errorPresenter) === 0) {
113: throw new NBadRequestException('Invalid request. Presenter is not achievable.');
114: }
115: }
116:
117: $this->requests[] = $request;
118: $this->onRequest($this, $request);
119:
120:
121: $presenterName = $request->getPresenterName();
122: try {
123: $this->presenter = $this->getPresenterFactory()->createPresenter($presenterName);
124: } catch (NInvalidPresenterException $e) {
125: throw new NBadRequestException($e->getMessage(), 404, $e);
126: }
127:
128: $this->getPresenterFactory()->getPresenterClass($presenterName);
129: $request->setPresenterName($presenterName);
130: $request->freeze();
131:
132:
133: $response = $this->presenter->run($request);
134: $this->onResponse($this, $response);
135:
136:
137: if ($response instanceof NForwardResponse) {
138: $request = $response->getRequest();
139: continue;
140:
141: } elseif ($response instanceof IPresenterResponse) {
142: $response->send($httpRequest, $httpResponse);
143: }
144: break;
145:
146: } catch (Exception $e) {
147:
148: $this->onError($this, $e);
149:
150: if (!$this->catchExceptions) {
151: $this->onShutdown($this, $e);
152: throw $e;
153: }
154:
155: if ($repeatedError) {
156: $e = new NApplicationException('An error occurred while executing error-presenter', 0, $e);
157: }
158:
159: if (!$httpResponse->isSent()) {
160: $httpResponse->setCode($e instanceof NBadRequestException ? $e->getCode() : 500);
161: }
162:
163: if (!$repeatedError && $this->errorPresenter) {
164: $repeatedError = TRUE;
165: if ($this->presenter instanceof NPresenter) {
166: try {
167: $this->presenter->forward(":$this->errorPresenter:", array('exception' => $e));
168: } catch (NAbortException $foo) {
169: $request = $this->presenter->getLastCreatedRequest();
170: }
171: } else {
172: $request = new NPresenterRequest(
173: $this->errorPresenter,
174: NPresenterRequest::FORWARD,
175: array('exception' => $e)
176: );
177: }
178:
179:
180: } else {
181: if ($e instanceof NBadRequestException) {
182: $code = $e->getCode();
183: } else {
184: $code = 500;
185: NDebugger::log($e, NDebugger::ERROR);
186: }
187: require dirname(__FILE__) . '/templates/error.phtml';
188: break;
189: }
190: }
191: } while (1);
192:
193: $this->onShutdown($this, isset($e) ? $e : NULL);
194: }
195:
196:
197:
198: 199: 200: 201:
202: final public function getRequests()
203: {
204: return $this->requests;
205: }
206:
207:
208:
209: 210: 211: 212:
213: final public function getPresenter()
214: {
215: return $this->presenter;
216: }
217:
218:
219:
220:
221:
222:
223:
224: 225: 226:
227: protected function getContext()
228: {
229: return $this->context;
230: }
231:
232:
233:
234: 235: 236: 237:
238: public function getRouter()
239: {
240: return $this->context->router;
241: }
242:
243:
244:
245: 246: 247: 248:
249: public function getPresenterFactory()
250: {
251: return $this->context->presenterFactory;
252: }
253:
254:
255:
256:
257:
258:
259:
260: 261: 262: 263: 264:
265: public function storeRequest($expiration = '+ 10 minutes')
266: {
267: $session = $this->context->session->getSection('Nette.Application/requests');
268: do {
269: $key = NStrings::random(5);
270: } while (isset($session[$key]));
271:
272: $session[$key] = end($this->requests);
273: $session->setExpiration($expiration, $key);
274: return $key;
275: }
276:
277:
278:
279: 280: 281: 282: 283:
284: public function restoreRequest($key)
285: {
286: $session = $this->context->session->getSection('Nette.Application/requests');
287: if (isset($session[$key])) {
288: $request = clone $session[$key];
289: unset($session[$key]);
290: $request->setFlag(NPresenterRequest::RESTORED, TRUE);
291: $this->presenter->sendResponse(new NForwardResponse($request));
292: }
293: }
294:
295: }
296: