Test Failed
Push — master ( 4c92de...3b4c18 )
by Sinnarasa
04:16
created

Router::addMiddleware()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace JetFire\Routing;
4
5
use JetFire\Routing\Matcher\ArrayMatcher;
6
use ReflectionClass;
7
use ReflectionMethod;
8
9
/**
10
 * Class Router
11
 * @package JetFire\Routing
12
 */
13
class Router
14
{
15
16
    /**
17
     * @var Route
18
     */
19
    public $route;
20
    /**
21
     * @var RouteCollection
22
     */
23
    public $collection;
24
    /**
25
     * @var ResponseInterface
26
     */
27
    public $response;
28
    /**
29
     * @var array
30
     */
31
    public $middlewareCollection = [];
32
    /**
33
     * @var array
34
     */
35
    public $matcher = [];
36
    /**
37
     * @var
38
     */
39
    public $dispatcher;
40
    /**
41
     * @var array
42
     */
43
    private $config = [
44
        'templateExtension' => ['.html', '.php', '.json', '.xml'],
45
        'templateCallback' => [],
46
        'di' => '',
47
        'generateRoutesPath' => false,
48
    ];
49
50
    /**
51
     * @param RouteCollection $collection
52
     * @param ResponseInterface $response
53
     * @param Route $route
54
     */
55
    public function __construct(RouteCollection $collection, ResponseInterface $response = null, Route $route = null)
56
    {
57
        $this->collection = $collection;
58
        $this->response = is_null($response) ? new Response() : $response;
59
        $this->route = is_null($route) ? new Route() : $route;
60
        $this->config['di'] = function ($class) {
61
            return new $class;
62
        };
63
    }
64
65
    /**
66
     * @param array $config
67
     */
68
    public function setConfig($config)
69
    {
70
        $this->config = array_merge($this->config, $config);
71
    }
72
73
    /**
74
     * @return array
75
     */
76
    public function getConfig()
77
    {
78
        return $this->config;
79
    }
80
81
    /**
82
     * @param object|array $middleware
83
     */
84
    public function setMiddleware($middleware)
85
    {
86
        $this->middlewareCollection = is_array($middleware)
87
            ? $middleware
88
            : [$middleware];
89
    }
90
91
    /**
92
     * @param MiddlewareInterface $middleware
93
     */
94
    public function addMiddleware(MiddlewareInterface $middleware)
95
    {
96
        $this->middlewareCollection[] = $middleware;
97
    }
98
99
    /**
100
     * @param object|array $matcher
101
     */
102
    public function setMatcher($matcher)
103
    {
104
        $this->matcher = is_array($matcher)
105
            ? $matcher
106
            : [$matcher];
107
    }
108
109
    /**
110
     * @param string $matcher
111
     */
112
    public function addMatcher($matcher)
113
    {
114
        $this->matcher[] = $matcher;
115
    }
116
117
    /**
118
     * @description main function
119
     */
120
    public function run()
121
    {
122
        $this->setUrl();
123
        if ($this->config['generateRoutesPath']) $this->collection->generateRoutesPath();
124
        if ($this->match() === true) {
125
            $this->callMiddleware('before');
126
            if (!in_array(substr($this->response->getStatusCode(), 0, 1), [3,4,5])) {
127
                $this->callTarget();
128
            }
129
            $this->callMiddleware('after');
130
        }else{
131
            $this->response->setStatusCode(404);
132
        }
133
        return $this->callResponse();
134
    }
135
136
    /**
137
     * @description call the middleware before and after the target
138
     * @param $action
139
     */
140
    private function callMiddleware($action)
141
    {
142
        foreach ($this->middlewareCollection as $middleware) {
143
            if ($middleware instanceof MiddlewareInterface) {
144
                foreach ($middleware->getCallbacks() as $callback) {
145
                    if (method_exists($middleware, $callback)) {
146
                        $response = call_user_func_array([$middleware, $callback], [$action]);
147
                        if($response instanceof ResponseInterface) {
148
                            $this->response = $response;
149
                        }
150
                    }
151
                }
152
            }
153
        }
154
    }
155
156
    /**
157
     * @param null $url
158
     */
159
    public function setUrl($url = null)
0 ignored issues
show
Coding Style introduced by
setUrl uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
setUrl uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
160
    {
161
        if (is_null($url))
162
            $url = (isset($_GET['url'])) ? $_GET['url'] : substr(str_replace(str_replace('/index.php', '', $_SERVER['SCRIPT_NAME']), '', $_SERVER['REQUEST_URI']), 1);
163
        $this->route->setUrl('/' . trim(explode('?', $url)[0], '/'));
164
    }
165
166
    /**
167
     * @return bool
168
     */
169
    public function match()
170
    {
171
        foreach ($this->matcher as $key => $matcher) {
172
            if (call_user_func([$this->matcher[$key], 'match'])) return true;
173
        }
174
        return false;
175
    }
176
177
    /**
178
     * @description call the target for the request uri
179
     */
180
    public function callTarget()
181
    {
182
        $target = is_array($this->route->getTarget('dispatcher')) ? $this->route->getTarget('dispatcher') : [$this->route->getTarget('dispatcher')];
183
        if (!empty($target)) {
184
            foreach ($target as $call) {
185
                $this->dispatcher = new $call($this);
186
                call_user_func([$this->dispatcher, 'call']);
187
            }
188
        }
189
    }
190
191
    /**
192
     * @param array $responses
193
     */
194
    public function setResponses($responses = [])
195
    {
196
        $this->route->addDetail('response_templates', $responses);
197
    }
198
199
    /**
200
     * @description set response code
201
     */
202
    public function callResponse()
203
    {
204
        if (isset($this->route->getDetail()['response_templates']) && isset($this->route->getDetail()['response_templates'][$code = $this->response->getStatusCode()])) {
205
            $this->route->setCallback($this->route->getDetail()['response_templates'][$code]);
206
            $matcher = null;
207
            foreach ($this->matcher as $instance) {
208
                if ($instance instanceof ArrayMatcher) {
209
                    $matcher = $instance;
210
                }
211
            }
212
            if (is_null($matcher)) {
213
                $matcher = new ArrayMatcher($this);
214
            }
215
            foreach (call_user_func([$matcher, 'getResolver']) as $match) {
216
                if (is_array($target = call_user_func_array([$matcher, $match], [$this->route->getCallback()]))) {
217
                    call_user_func_array([$matcher, 'setTarget'], [$target]);
218
                    $this->callTarget();
219
                    break;
220
                }
221
            }
222
            $this->response->setStatusCode($code);
223
        }
224
225
        return $this->response->send();
226
    }
227
}
228