1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Application;
9:
10: use Nette;
11:
12:
13: 14: 15:
16: class Application extends Nette\Object
17: {
18:
19: public static $maxLoop = 20;
20:
21:
22: public $catchExceptions;
23:
24:
25: public $errorPresenter;
26:
27:
28: public $onStartup;
29:
30:
31: public $onShutdown;
32:
33:
34: public $onRequest;
35:
36:
37: public $onPresenter;
38:
39:
40: public $onResponse;
41:
42:
43: public $onError;
44:
45:
46: private $requests = array();
47:
48:
49: private $presenter;
50:
51:
52: private $httpRequest;
53:
54:
55: private $httpResponse;
56:
57:
58: private $presenterFactory;
59:
60:
61: private $router;
62:
63:
64: public function __construct(IPresenterFactory $presenterFactory, IRouter $router, Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse)
65: {
66: $this->httpRequest = $httpRequest;
67: $this->httpResponse = $httpResponse;
68: $this->presenterFactory = $presenterFactory;
69: $this->router = $router;
70: }
71:
72:
73: 74: 75: 76:
77: public function run()
78: {
79: try {
80: $this->onStartup($this);
81: $this->processRequest($this->createInitialRequest());
82: $this->onShutdown($this);
83:
84: } catch (\Exception $e) {
85: $this->onError($this, $e);
86: if ($this->catchExceptions && $this->errorPresenter) {
87: try {
88: $this->processException($e);
89: $this->onShutdown($this, $e);
90: return;
91:
92: } catch (\Exception $e) {
93: $this->onError($this, $e);
94: }
95: }
96: $this->onShutdown($this, $e);
97: throw $e;
98: }
99: }
100:
101:
102: 103: 104:
105: public function createInitialRequest()
106: {
107: $request = $this->router->match($this->httpRequest);
108:
109: if (!$request instanceof Request) {
110: throw new BadRequestException('No route for HTTP request.');
111: }
112: $name = $request->getPresenterName();
113: if (strcasecmp($name, $this->errorPresenter) === 0
114: || (Nette\Utils\Strings::startsWith($name, 'Nette:') && $name !== 'Nette:Micro')
115: ) {
116: throw new BadRequestException('Invalid request. Presenter is not achievable.');
117: }
118:
119: try {
120: $this->presenterFactory->getPresenterClass($name);
121: } catch (InvalidPresenterException $e) {
122: throw new BadRequestException($e->getMessage(), 0, $e);
123: }
124:
125: return $request;
126: }
127:
128:
129: 130: 131:
132: public function processRequest(Request $request)
133: {
134: if (count($this->requests) > self::$maxLoop) {
135: throw new ApplicationException('Too many loops detected in application life cycle.');
136: }
137:
138: $this->requests[] = $request;
139: $this->onRequest($this, $request);
140:
141: $this->presenter = $this->presenterFactory->createPresenter($request->getPresenterName());
142: $this->onPresenter($this, $this->presenter);
143: $response = $this->presenter->run($request);
144:
145: if ($response instanceof Responses\ForwardResponse) {
146: $this->processRequest($response->getRequest());
147:
148: } elseif ($response) {
149: $this->onResponse($this, $response);
150: $response->send($this->httpRequest, $this->httpResponse);
151: }
152: }
153:
154:
155: 156: 157:
158: public function processException(\Exception $e)
159: {
160: if (!$e instanceof BadRequestException && $this->httpResponse instanceof Nette\Http\Response) {
161: $this->httpResponse->warnOnBuffer = FALSE;
162: }
163: if (!$this->httpResponse->isSent()) {
164: $this->httpResponse->setCode($e instanceof BadRequestException ? ($e->getCode() ?: 404) : 500);
165: }
166:
167: $args = array('exception' => $e, 'request' => end($this->requests) ?: NULL);
168: if ($this->presenter instanceof UI\Presenter) {
169: try {
170: $this->presenter->forward(":$this->errorPresenter:", $args);
171: } catch (AbortException $foo) {
172: $this->processRequest($this->presenter->getLastCreatedRequest());
173: }
174: } else {
175: $this->processRequest(new Request($this->errorPresenter, Request::FORWARD, $args));
176: }
177: }
178:
179:
180: 181: 182: 183:
184: public function getRequests()
185: {
186: return $this->requests;
187: }
188:
189:
190: 191: 192: 193:
194: public function getPresenter()
195: {
196: return $this->presenter;
197: }
198:
199:
200:
201:
202:
203: 204: 205: 206:
207: public function getRouter()
208: {
209: return $this->router;
210: }
211:
212:
213: 214: 215: 216:
217: public function getPresenterFactory()
218: {
219: return $this->presenterFactory;
220: }
221:
222: }
223: