1 | <?php |
||
16 | class Dispatcher |
||
17 | { |
||
18 | // Garrrr! An arrrray! |
||
19 | private $config = array(); |
||
20 | |||
21 | /** @var ServerRequestInterface $request */ |
||
22 | private $request; |
||
23 | |||
24 | /** @var Controller */ |
||
25 | private $controller; |
||
26 | |||
27 | /** @var ResponseInterface $response */ |
||
28 | private $response; |
||
29 | |||
30 | /** |
||
31 | * Dispatcher constructor. |
||
32 | * @param ServerRequestInterface $request |
||
33 | * @param ResponseInterface $response |
||
34 | * @throws Filter\Exception |
||
35 | */ |
||
36 | 15 | public function __construct(ServerRequestInterface $request, ResponseInterface $response) |
|
55 | |||
56 | |||
57 | /** |
||
58 | * Gaaarrr! Check the Navigator be readin' the map! |
||
59 | * @return null|void |
||
60 | */ |
||
61 | 2 | public function checkNavigator() |
|
62 | 2 | { |
|
63 | // can we find th' darned controller? |
||
64 | 1 | if (!$this->checkControllerExists()) { |
|
65 | 1 | $this->setNotFound(); |
|
66 | 1 | return; |
|
67 | } |
||
68 | |||
69 | // gaaarr! there be the controller! |
||
70 | 1 | $this->controller = new $this->config['controller_name']($this->request); |
|
71 | 1 | $this->controller->params = isset($this->config['params']) ? $this->config['params'] : null; |
|
72 | |||
73 | // where's the bloody action? |
||
74 | 1 | if (!$this->checkActionExists()) { |
|
75 | 1 | $this->setNotFound(); |
|
76 | 1 | } |
|
77 | 1 | return null; |
|
78 | } |
||
79 | |||
80 | |||
81 | /** |
||
82 | * @return bool |
||
83 | */ |
||
84 | 2 | private function checkControllerExists() |
|
88 | |||
89 | |||
90 | /** |
||
91 | * @return bool |
||
92 | */ |
||
93 | 2 | private function checkActionExists() |
|
97 | |||
98 | |||
99 | /** |
||
100 | * @return string |
||
101 | * @throws \Exception |
||
102 | */ |
||
103 | 4 | private function distributeBooty() |
|
104 | 4 | { |
|
105 | /** @var \stdClass $viewVars */ |
||
106 | 4 | $viewVars = $this->controller->view; |
|
107 | |||
108 | 4 | if ($viewVars instanceof ResponseInterface) { |
|
109 | 1 | $this->response = $viewVars; |
|
110 | 1 | return $this->sendResponse(); |
|
111 | } |
||
112 | |||
113 | 3 | $responseBody = $this->controller->getBody(); |
|
114 | |||
115 | 3 | if ($this->controller->hasViewEnabled()) { |
|
116 | 2 | $view = $this->config['controller'] . '/' . $this->config['action']; |
|
117 | try { |
||
118 | 2 | $responseBody = $this->controller->getViewEngine()->render($view, (array) $viewVars); |
|
119 | 2 | } catch (Exception $e) { |
|
120 | throw $e; |
||
121 | } |
||
122 | 2 | } |
|
123 | |||
124 | 3 | if ($this->controller->hasLayoutEnabled()) { |
|
125 | 2 | $responseBody = $this->templateCheck($this->controller, $responseBody); |
|
126 | 2 | } |
|
127 | 3 | $this->prepareResponse($responseBody); |
|
128 | 3 | $this->sendResponse(); |
|
129 | 3 | } |
|
130 | |||
131 | |||
132 | /** |
||
133 | * @throws Exception |
||
134 | */ |
||
135 | 2 | public function fireCannons() |
|
136 | 2 | { |
|
137 | try { |
||
138 | // Garr! Check the route with th' navigator |
||
139 | 1 | $this->checkNavigator(); |
|
140 | |||
141 | // Fire cannons t' th' controller action |
||
142 | 1 | $this->plunderEnemyShip(); |
|
143 | |||
144 | // Share the loot! send out th' response |
||
145 | 1 | $this->distributeBooty(); |
|
146 | 1 | } catch (Exception $e) { |
|
147 | $this->sinkingShip($e); |
||
148 | } |
||
149 | 1 | } |
|
150 | |||
151 | /** |
||
152 | * @param $booty |
||
153 | */ |
||
154 | 3 | private function prepareResponse($booty) |
|
160 | |||
161 | |||
162 | 4 | private function sendResponse() |
|
167 | |||
168 | 4 | private function setHeaders() |
|
174 | |||
175 | 4 | private function setStatusCode() |
|
176 | 4 | { |
|
177 | 4 | $status = $this->controller->getStatusCode(); |
|
178 | 4 | if ($status != 200) { |
|
179 | try { |
||
180 | 1 | $this->response = $this->response->withStatus($status); |
|
181 | 1 | } catch (Exception $e) { |
|
182 | 1 | $this->response = $this->response->withStatus(500); |
|
183 | } |
||
184 | |||
185 | 1 | } |
|
186 | 4 | } |
|
187 | |||
188 | |||
189 | 3 | private function plunderEnemyShip() |
|
190 | 3 | { |
|
191 | // run th' controller action |
||
192 | 3 | $action = $this->config['action_name']; |
|
193 | |||
194 | 3 | $this->controller->init(); |
|
195 | 3 | $vars = $this->controller->$action(); |
|
196 | |||
197 | 3 | if (is_array($vars)) { |
|
198 | |||
199 | 1 | $viewVars = (array) $this->controller->view; |
|
200 | 1 | $view = (object) array_merge($vars, $viewVars); |
|
201 | 1 | $this->controller->view = $view; |
|
202 | |||
203 | 3 | } elseif ($vars instanceof ResponseInterface) { |
|
204 | |||
205 | 1 | $this->controller->view = $vars; |
|
206 | |||
207 | 1 | } |
|
208 | |||
209 | 3 | $this->controller->postDispatch(); |
|
210 | 3 | } |
|
211 | |||
212 | /** |
||
213 | * @param Exception $e |
||
214 | * @return string |
||
215 | * @throws Exception |
||
216 | */ |
||
217 | 1 | public function sinkingShip(Exception $e) |
|
232 | |||
233 | |||
234 | /** |
||
235 | * @param Controller $controller |
||
236 | * @param string $content |
||
237 | * @return string |
||
238 | */ |
||
239 | 3 | private function templateCheck($controller, $content) |
|
240 | 3 | { |
|
241 | 3 | $responseBody = ''; |
|
242 | //check we be usin' th' templates in th' config |
||
243 | 3 | $templates = Registry::ahoy()->get('templates'); |
|
244 | 3 | $template = $this->getTemplateName($templates); |
|
245 | 3 | if ($template !== null) { |
|
246 | 3 | $responseBody = $controller->getViewEngine()->render('layouts/' . $template, array('content' => $content)); |
|
247 | 3 | } |
|
248 | 3 | return $responseBody; |
|
249 | } |
||
250 | |||
251 | /** |
||
252 | * @param mixed $templates |
||
253 | * @return string|null |
||
254 | */ |
||
255 | 4 | private function getTemplateName($templates) |
|
264 | |||
265 | /** |
||
266 | * Sets controller to error and action to not found |
||
267 | * @return void |
||
268 | */ |
||
269 | 2 | private function setNotFound() |
|
278 | } |
||
279 |
Let’s assume that you have a directory layout like this:
and let’s assume the following content of
Bar.php
:If both files
OtherDir/Foo.php
andSomeDir/Foo.php
are loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php
However, as
OtherDir/Foo.php
does not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php
, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: