Completed
Push — master ( e1bc0f...1d405f )
by Derek Stephen
01:42
created

Dispatcher::checkNavigator()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 17
ccs 9
cts 9
cp 1
rs 9.4285
cc 3
eloc 8
nc 3
nop 0
crap 3
1
<?php
2
3
namespace Bone\Mvc;
4
5
use Bone\Filter;
6
use Exception;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Bone\Mvc\Exception.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/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 before OtherDir/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:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
7
use ReflectionClass;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Psr\Http\Message\ResponseInterface;
10
use Zend\Diactoros\Response\SapiEmitter;
11
12
/**
13
 * Class Dispatcher
14
 * @package Bone\Mvc
15
 */
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 11
    public function __construct(ServerRequestInterface $request, ResponseInterface $response)
32 11
    {
33 11
        $this->request = $request;
34 11
        $this->response = $response;
35
36 11
        $router = new Router($request);
37 11
        $router->parseRoute();
38
39
        // what controller be we talkin' about?
40 11
        $filtered = Filter::filterString($router->getController(), 'DashToCamelCase');
41 11
        $this->config['controller_name'] = '\App\Controller\\' . ucwords($filtered) . 'Controller';
42
43
        // whit be yer action ?
44 11
        $filtered = Filter::filterString($router->getAction(), 'DashToCamelCase');
45 11
        $this->config['action_name'] = $filtered . 'Action';
46 11
        $this->config['controller'] = $router->getController();
47 11
        $this->config['action'] = $router->getAction();
48 11
    }
49
50
51
    /**
52
     *  Gaaarrr! Check the Navigator be readin' the map!
53
     * @return null|void
54
     */
55 2
    public function checkNavigator()
56 2
    {
57
        // can we find th' darned controller?
58 1
        if (!$this->checkControllerExists()) {
59 1
            $this->setNotFound();
60 1
            return;
61
        }
62
63
        // gaaarr! there be the controller!
64 1
        $this->controller = new $this->config['controller_name']($this->request);
65
66
        // where's the bloody action?
67 1
        if (!$this->checkActionExists()) {
68 1
            $this->setNotFound();
69
        }
70 1
        return null;
71
    }
72
73
74
    /**
75
     * @return bool
76
     */
77 2
    private function checkControllerExists()
78 2
    {
79 2
        return class_exists($this->config['controller_name']);
80
    }
81
82
83
    /**
84
     * @return bool
85
     */
86 2
    private function checkActionExists()
87 2
    {
88 2
        return method_exists($this->controller, $this->config['action_name']);
89
    }
90
91
92
    /**
93
     * @return string
94
     * @throws \Exception
95
     */
96 3
    private function getResponseBody()
97 3
    {
98
        /** @var \stdClass $view_vars */
99 3
        $view_vars = $this->controller->view;
100
101 3
        $response_body = $this->controller->getBody();
102
103 3
        if ($this->controller->hasViewEnabled()) {
104 2
            $view = $this->config['controller'] . '/' . $this->config['action'];
105
            try {
106 2
                $response_body = $this->controller->getViewEngine()->render($view, (array) $view_vars);
107 1
            } catch (Exception $e) {
108 1
                throw $e;
109
            }
110
        }
111
112 3
        if ($this->controller->hasLayoutEnabled()) {
113 2
            $response_body = $this->templateCheck($this->controller, $response_body);
114
        }
115 3
        return $response_body;
116
    }
117
118
119
    /**
120
     *
121
     */
122 2
    public function fireCannons()
123 2
    {
124
        try {
125
            // Garr! Check the route with th' navigator
126 1
            $this->checkNavigator();
127
128
            // Fire cannons t' th' controller action
129 1
            $this->plunderEnemyShip();
130
131
            // See what treasure we have plundered
132 1
            $booty = $this->getResponseBody();
133 1
        } catch (Exception $e) {
134 1
            $booty = $this->sinkingShip($e);
135
        }
136
137
138
        // report back to th' cap'n
139 1
        $this->response->getBody()->write($booty);
140 1
        $this->setHeaders();
141 1
        return $this->sendResponse();
142
    }
143
144
    /**
145
     * @return string
146
     */
147 1
    private function sendResponse()
148 1
    {
149 1
        $emitter = new SapiEmitter();
150 1
        ob_start();
151 1
        $emitter->emit($this->response);
152 1
        $content = ob_get_contents();
153 1
        ob_end_clean();
154 1
        return  $content;
155
    }
156
157 1
    private function setHeaders()
158 1
    {
159 1
        foreach ($this->controller->getHeaders() as $key => $value) {
160 1
            $this->response = $this->response->withHeader($key, $value);
161
        }
162 1
    }
163
164
165 2
    private function plunderEnemyShip()
166 2
    {
167
        // run th' controller action
168 2
        $action = $this->config['action_name'];
169 2
        $this->controller->init();
170 2
        $vars = $this->controller->$action();
171 2
        if (is_array($vars)) {
172 1
            $viewVars = (array) $this->controller->view;
173 1
            $view = (object) array_merge($vars, $viewVars);
174 1
            $this->controller->view =$view;
175
        }
176 2
        $this->controller->postDispatch();
177 2
    }
178
179
180 2
    public function sinkingShip($e)
181 2
    {
182 1
        $controllerName = class_exists('\App\Controller\ErrorController') ? 'App\Controller\ErrorController' : 'Bone\Mvc\Controller';
183 1
        $this->controller = new $controllerName($this->request);
184 1
        $this->controller->setParam('error', $e);
185 1
        $reflection = new ReflectionClass(get_class($this->controller));
186 1
        $method = $reflection->getMethod('errorAction');
187 1
        $method->setAccessible(true);
188 1
        $method->invokeArgs($this->controller, []);
189 1
        $this->controller->error = $e;
190 1
        $this->config['controller'] = 'error';
191 1
        $this->config['action'] = 'error';
192 1
        return $this->getResponseBody();
193
    }
194
195
196
    /**
197
     * @param Controller $controller
198
     * @param string $content
199
     * @return string
200
     */
201 3
    private function templateCheck($controller, $content)
202 3
    {
203 3
        $response_body = '';
204
        //check we be usin' th' templates in th' config
205 3
        $templates = Registry::ahoy()->get('templates');
206 3
        $template = $this->getTemplateName($templates);
207 3
        if ($template !== null) {
208 3
            $response_body = $controller->getViewEngine()->render('layouts/' . $template, array('content' => $content));
209
        }
210 3
        return $response_body;
211
    }
212
213
    /**
214
     * @param mixed $templates
215
     * @return string|null
216
     */
217 4
    private function getTemplateName($templates)
218 4
    {
219 4
        if (is_null($templates)) {
220 1
            return null;
221 4
        } elseif (is_array($templates)) {
222 1
            return (string) $templates[0];
223
        }
224 4
        return (string) $templates;
225
    }
226
227
    /**
228
     * Sets controller to error and action to not found
229
     * @return void
230
     */
231 2
    private function setNotFound()
232 2
    {
233 2
        $this->config['controller_name'] = class_exists('\App\Controller\ErrorController') ? '\App\Controller\ErrorController' : '\Bone\Mvc\Controller';
234 2
        $this->config['action_name'] = 'notFoundAction';
235 2
        $this->config['controller'] = 'error';
236 2
        $this->config['action'] = 'not-found';
237 2
        $this->controller = new $this->config['controller_name']($this->request);
238 2
    }
239
}
240