Router::getParser()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
crap 1
1
<?php
2
namespace HakimCh\Http;
3
4
use Iterator;
5
6
class Router
7
{
8
    protected $routes = [];
9
    protected $namedRoutes = [];
10
    protected $basePath = '';
11
    protected $all = ['get', 'post'];
12
    protected $server;
13
    /**
14
     * @var RouterParser
15
     */
16
    private $parser;
17
18
    /**
19
     * Create router in one call from config.
20
     *
21
     * @param RouterParser $parser
22
     * @param array $routes
23
     * @param string $basePath
24
     * @param array|null $server
25
     */
26 19
    public function __construct(RouterParser $parser, $routes = [], $basePath = '', $server = null)
27
    {
28 19
        $this->setRoutes($routes);
29 19
        $this->setBasePath($basePath);
30 19
        $this->parser = $parser;
31 19
        $this->server = $server;
32 19
    }
33
34
    /**
35
     * Map a route to a target
36
     *
37
     * @param string $method One of 5 HTTP Methods, or a pipe-separated list of multiple HTTP Methods (GET|POST|PATCH|PUT|DELETE)
38
     * @param string $route The route regex, custom regex must start with an @. You can use multiple pre-set regex filters, like [i:id]
39
     * @param mixed $target The target where this route should point to. Can be anything.
40
     * @param string $routeName Optional name of this route. Supply if you want to reverse route this url in your application.
41
     */
42 16
    public function map($method, $route, $target, $routeName = null)
43
    {
44 16
        if (is_string($routeName)) {
45 15
            $this->handleException($routeName, "Can not redeclare route '%s'", true);
46 15
            $this->namedRoutes[$routeName] = $route;
47 15
        }
48
49 16
        $this->routes[] = array($method, $route, $target, $routeName);
50 16
    }
51
52
    /**
53
     * Reversed routing
54
     * Generate the URL for a named route. Replace regexes with supplied parameters
55
     *
56
     * @param string $routeName The name of the route.
57
     * @param array $params Associative array of parameters to replace placeholders with.
58
     *
59
     * @return string The URL of the route with named parameters in place.
60
     */
61 3
    public function generate($routeName, array $params = [])
62
    {
63 3
        $this->handleException($routeName, "Route '%s' does not exist.", false);
64
65 2
        $route = $this->namedRoutes[$routeName];
66
67 2
        return $this->parser->generateUrl($this->basePath, $route, $params);
68
    }
69
70
    /**
71
     * Match a given Request Url against stored routes
72
     * @param string $requestUrl
73
     * @param string $requestMethod
74
     *
75
     * @return array|boolean Array with route information on success, false on failure (no match).
76
     */
77 9
    public function match($requestUrl = null, $requestMethod = null)
78
    {
79 9
        $requestUrl = $this->getRequestUrl($requestUrl);
80
81
        // set Request Method if it isn't passed as a parameter
82 9
        if (is_null($requestMethod)) {
83 1
            $requestMethod = $this->server['REQUEST_METHOD'];
84 1
        }
85
86 9
        foreach ($this->routes as $handler) {
87 9
            if (!$this->parser->methodMatch($handler[0], $requestMethod, $handler[1], $requestUrl)) {
88 7
                continue;
89
            }
90
91
            return array(
92 9
                'target' => $handler[2],
93 9
                'params' => array_filter($this->parser->getParams(), function ($k) {
94 8
                    return !is_numeric($k);
95 9
                }, ARRAY_FILTER_USE_KEY),
96 9
                'name'   => $handler[3]
97 9
            );
98 6
        }
99
100 6
        return false;
101
    }
102
103
    /**
104
     * @param $method
105
     * @param $arguments
106
     *
107
     * @throws RouterException
108
     */
109
    public function __call($method, $arguments)
110
    {
111
        if (!in_array($method, array('get', 'post', 'delete', 'put', 'patch', 'update', 'all'))) {
112
            throw new RouterException($method . ' not exist in the '. __CLASS__);
113
        }
114
115
        $methods = $method == 'all' ? implode('|', $this->all) : $method;
116
117
        $route = array_merge([$methods], $arguments);
118
119
        call_user_func_array([$this, 'map'], $route);
120
    }
121
122
    /**
123
     * Retrieves all routes.
124
     * Useful if you want to process or display routes.
125
     *
126
     * @return array All routes.
127
     */
128 4
    public function getRoutes()
129
    {
130 4
        return $this->routes;
131
    }
132
133
    /**
134
     * Add multiple routes at once from array in the following format:
135
     *
136
     *   $routes = array(
137
     *      array($method, $route, $target, $name)
138
     *   );
139
     *
140
     * @param array|Iterator $routes
141
     *
142
     * @return void
143
     */
144 19
    public function setRoutes($routes)
145
    {
146 19
        if (!is_array($routes) && !$routes instanceof Iterator) {
147 1
            throw new RouterException('Routes should be an array or an instance of Iterator');
148
        }
149 19
        if (!empty($routes)) {
150 2
            foreach ($routes as $route) {
151 2
                call_user_func_array(array($this, 'map'), $route);
152 2
            }
153 2
        }
154 19
    }
155
156
    /**
157
     * Set the base path.
158
     * Useful if you are running your application from a subdirectory.
159
     *
160
     * @param $basePath
161
     */
162 19
    public function setBasePath($basePath)
163
    {
164 19
        $this->basePath = $basePath;
165 19
    }
166
167
    /**
168
     * @param $routeName
169
     * @param $message
170
     * @param bool $cmpTo
171
     *
172
     * @throws RouterException
173
     */
174 16
    private function handleException($routeName, $message, $cmpTo)
175
    {
176 16
        if (array_key_exists($routeName, $this->namedRoutes) === $cmpTo) {
177 2
            throw new RouterException(sprintf($message, $routeName));
178
        }
179 15
    }
180
181
    /**
182
     * @param $requestUrl
183
     *
184
     * @return mixed
185
     */
186 9
    private function getRequestUrl($requestUrl = null)
187
    {
188
        // set Request Url if it isn't passed as parameter
189 9
        if (is_null($requestUrl)) {
190 1
            $requestUrl = parse_url($this->server['REQUEST_URI'], PHP_URL_PATH);
191 1
        }
192
193 9
        return str_replace($this->basePath, '', strtok($requestUrl, '?'));
194
    }
195
196
    /**
197
     * @return RouterParser
198
     */
199 2
    public function getParser()
200
    {
201 2
        return $this->parser;
202
    }
203
204
205 1
    public function getNamedRoutes()
206
    {
207 1
        return $this->namedRoutes;
208
    }
209
210 1
    public function getBasePath()
211
    {
212 1
        return $this->basePath;
213
    }
214
215 1
    public function setServer($server)
216
    {
217 1
        $this->server = $server;
218 1
    }
219
}
220