Completed
Push — master ( 4f01ad...914da5 )
by Filipe
02:36
created

Dispatcher::setViewVars()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
ccs 8
cts 8
cp 1
rs 9.4285
cc 1
eloc 8
nc 1
nop 2
crap 1
1
<?php
2
3
/**
4
 * This file is part of slick/mvc package
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Slick\Mvc;
11
12
use Aura\Router\Route;
13
use Psr\Http\Message\ResponseInterface;
14
use Psr\Http\Message\ServerRequestInterface;
15
use Slick\Http\Server\AbstractMiddleware;
16
use Slick\Http\Server\MiddlewareInterface;
17
use Slick\Mvc\Exception\ControllerMethodNotFoundException;
18
use Slick\Mvc\Exception\ControllerNotFoundException;
19
use Slick\Mvc\Exception\InvalidControllerException;
20
21
/**
22
 * Dispatcher
23
 *
24
 * @package Slick\Mvc
25
 * @author  Filipe Silva <[email protected]>
26
 */
27
class Dispatcher extends AbstractMiddleware implements MiddlewareInterface
28
{
29
30
    /**
31
     * @var string
32
     */
33
    protected $namespace;
34
35
    /**
36
     * @var string
37
     */
38
    protected $action;
39
40
    /**
41
     * @var string
42
     */
43
    protected $controller;
44
45
    /**
46
     * @var string
47
     */
48
    protected $args = [];
49
50
    /**
51
     * Handles a Request and updated the response
52
     *
53
     * @param ServerRequestInterface $request
54
     * @param ResponseInterface $response
55
     *
56
     * @return ResponseInterface
57
     */
58 10
    public function handle(
59
        ServerRequestInterface $request, ResponseInterface $response
60
    )
61
    {
62
        /** @var Route $route */
63 10
        $route = $request->getAttribute('route', false);
64 10
        $this->setAttributes($route);
65 10
        $class = $this->namespace.'\\'.$this->controller;
66 10
        $controller = $this->createController($class);
67 6
        $controller->register($request, $response);
68
69 6
        $this->checkAction($class);
70
71 4
        call_user_func_array([$controller, $this->action], $this->args);
72 4
        $request = $controller->getRequest();
73 4
        $request = $this->setViewVars($controller, $request);
74
75 4
        return $this->executeNext(
76 4
            $request,
77 4
            $controller->getResponse()
78 4
        );
79
80
    }
81
82
    /**
83
     * Sets the data values into request
84
     * 
85
     * @param ControllerInterface $controller
86
     * @param ServerRequestInterface $request
87
     * 
88
     * @return ServerRequestInterface|static
89
     */
90 4
    protected function setViewVars(
91
        ControllerInterface $controller, ServerRequestInterface $request
92
    ) {
93 4
        $key = $controller::REQUEST_ATTR_VIEW_DATA;
94 4
        $data = $request->getAttribute($key, []);
95 4
        $request = $request->withAttribute(
96 4
            $key,
97 4
            array_merge($data, $controller->getViewVars())
98 4
        );
99 4
        return $request;
100
    }
101
102
    /**
103
     * Creates the controller with provided class name
104
     *
105
     * @param string $controller
106
     *
107
     * @return ControllerInterface
108
     */
109 10
    protected function createController($controller)
110
    {
111 10
        $this->checkClass($controller);
112 8
        $handler = new $controller;
113 8
        if (! $handler instanceof ControllerInterface) {
114 2
            throw new InvalidControllerException(
115 2
                "The class '{$controller}' does not implement ControllerInterface."
116 2
            );
117
        }
118 6
        return $handler;
119
    }
120
121
    /**
122
     * Check if class exists
123
     *
124
     * @param string $className
125
     * @return $this|self|Dispatcher
126
     */
127 10
    protected function checkClass($className)
128
    {
129 10
        if ($className == '\\' || !class_exists($className)) {
130 2
            throw new ControllerNotFoundException(
131 2
                "The controller '{$className}' was not found."
132 2
            );
133
        }
134 8
        return $this;
135
    }
136
137
    /**
138
     * @param Route $route
139
     *
140
     * @return $this|self|Dispatcher
141
     */
142 10
    protected function setAttributes(Route $route)
143
    {
144 10
        $this->namespace = array_key_exists('namespace', $route->attributes)
145 10
            ? $route->attributes['namespace']
146 10
            : null;
147 10
        $this->controller = array_key_exists('controller', $route->attributes)
148 10
            ? ucfirst($this->normalize($route->attributes['controller']))
149 10
            : null;
150 10
        $this->action = array_key_exists('action', $route->attributes)
151 10
            ? $this->normalize($route->attributes['action'])
152 10
            : null;
153 10
        $this->args  = array_key_exists('args', $route->attributes)
154 10
            ? $route->attributes['args']
155 10
            : [];
156 10
        return $this;
157
    }
158
159
    /**
160
     * Normalize controller/action names
161
     *
162
     * @param string $name
163
     * @return string
164
     */
165 8
    protected function normalize($name)
166
    {
167 8
        $name = str_replace(['_', '-'], '#', $name);
168 8
        $words = explode('#', $name);
169
        array_walk($words, function(&$item){$item = ucfirst($item);});
170 8
        return lcfirst(implode('', $words));
171
    }
172
173
    /**
174
     * Check if action is defined in the controller
175
     *
176
     * @param string $className
177
     *
178
     * @return Dispatcher
179
     */
180 6
    protected function checkAction($className)
181
    {
182 6
        if (!in_array($this->action, get_class_methods($className))) {
183 2
            throw new ControllerMethodNotFoundException(
184 2
                "The method {$this->action} is not defined in ".
185 2
                "'{$className}' controller."
186 2
            );
187
        }
188 4
        return $this;
189
    }
190
}