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