Completed
Push — master ( c35a3d...e1bc0f )
by Derek Stephen
03:44
created

Dispatcher::fireCannons()   B

Complexity

Conditions 2
Paths 4

Size

Total Lines 27
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
dl 0
loc 27
ccs 15
cts 15
cp 1
rs 8.8571
c 3
b 0
f 0
cc 2
eloc 15
nc 4
nop 0
crap 2
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
            // Where be the navigator? Be we on course?
126 1
            $this->checkNavigator();
127
128
            // boom! direct hit Cap'n! Be gettin' the booty!
129 1
            $this->plunderEnemyShip();
130
131
            // show th' cap'n th' booty
132 1
            $booty = $this->getResponseBody();
133 1
        } catch (Exception $e) {
134 1
            $booty = $this->sinkingShip($e);
135
        }
136
137 1
        $this->response->getBody()->write($booty);
138
139
        // report back to th' cap'n
140 1
        $this->setHeaders();
141
142 1
        $emitter = new SapiEmitter();
143 1
        ob_start();
144 1
        $emitter->emit($this->response);
145 1
        $content = ob_get_contents();
146 1
        ob_end_clean();
147 1
        return  $content;
148
    }
149
150 1
    private function setHeaders()
151 1
    {
152 1
        foreach ($this->controller->getHeaders() as $key => $value) {
153 1
            $this->response = $this->response->withHeader($key, $value);
154
        }
155 1
    }
156
157
158 2
    private function plunderEnemyShip()
159 2
    {
160
        // run th' controller action
161 2
        $action = $this->config['action_name'];
162 2
        $this->controller->init();
163 2
        $vars = $this->controller->$action();
164 2
        if (is_array($vars)) {
165 1
            $viewVars = (array) $this->controller->view;
166 1
            $view = (object) array_merge($vars, $viewVars);
167 1
            $this->controller->view =$view;
168
        }
169 2
        $this->controller->postDispatch();
170 2
    }
171
172
173 2
    public function sinkingShip($e)
174 2
    {
175 1
        $controllerName = class_exists('\App\Controller\ErrorController') ? 'App\Controller\ErrorController' : 'Bone\Mvc\Controller';
176 1
        $this->controller = new $controllerName($this->request);
177 1
        $this->controller->setParam('error', $e);
178 1
        $reflection = new ReflectionClass(get_class($this->controller));
179 1
        $method = $reflection->getMethod('errorAction');
180 1
        $method->setAccessible(true);
181 1
        $method->invokeArgs($this->controller, []);
182 1
        $this->controller->error = $e;
183 1
        $this->config['controller'] = 'error';
184 1
        $this->config['action'] = 'error';
185 1
        return $this->getResponseBody();
186
    }
187
188
189
    /**
190
     * @param Controller $controller
191
     * @param string $content
192
     * @return string
193
     */
194 3
    private function templateCheck($controller, $content)
195 3
    {
196 3
        $response_body = '';
197
        //check we be usin' th' templates in th' config
198 3
        $templates = Registry::ahoy()->get('templates');
199 3
        $template = $this->getTemplateName($templates);
200 3
        if ($template !== null) {
201 3
            $response_body = $controller->getViewEngine()->render('layouts/' . $template, array('content' => $content));
202
        }
203 3
        return $response_body;
204
    }
205
206
    /**
207
     * @param mixed $templates
208
     * @return string|null
209
     */
210 4
    private function getTemplateName($templates)
211 4
    {
212 4
        if (is_null($templates)) {
213 1
            return null;
214 4
        } elseif (is_array($templates)) {
215 1
            return (string) $templates[0];
216
        }
217 4
        return (string) $templates;
218
    }
219
220
    /**
221
     * Sets controller to error and action to not found
222
     * @return void
223
     */
224 2
    private function setNotFound()
225 2
    {
226 2
        $this->config['controller_name'] = class_exists('\App\Controller\ErrorController') ? '\App\Controller\ErrorController' : '\Bone\Mvc\Controller';
227 2
        $this->config['action_name'] = 'notFoundAction';
228 2
        $this->config['controller'] = 'error';
229 2
        $this->config['action'] = 'not-found';
230 2
        $this->controller = new $this->config['controller_name']($this->request);
231 2
    }
232
}
233