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