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