RouteCollection::dispatch()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 3
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
namespace Wandu\Router;
3
4
use FastRoute\DataGenerator\GroupCountBased as GCBGenerator;
5
use IteratorAggregate;
6
use Psr\Http\Message\ServerRequestInterface;
7
use Wandu\Router\Contracts\Dispatchable;
8
use Wandu\Router\Contracts\LoaderInterface;
9
use Wandu\Router\Contracts\ResponsifierInterface;
10
use Wandu\Router\Contracts\Routable;
11
use Wandu\Router\Contracts\RouteFluent;
12
use Wandu\Router\Path\Pattern;
13
14
class RouteCollection implements Routable, IteratorAggregate, Dispatchable
15
{
16
    /** @var \Wandu\Router\RouteCollection[] */
17
    protected $routers = [];
18
19
    /** @var \Wandu\Router\Route[] */
20
    protected $routes = [];
21
22
    /** @var string */
23
    protected $prefix;
24
    
25
    /** @var array */
26
    protected $middlewares;
27
    
28
    /** @var array */
29
    protected $domains;
30
31
    /**
32
     * @param string $prefix
33
     * @param array $middlewares
34
     * @param array $domains
35
     */
36 21
    public function __construct($prefix = '', array $middlewares = [], array $domains = [])
37
    {
38 21
        $this->prefix = $prefix;
39 21
        $this->middlewares = $middlewares;
40 21
        $this->domains = $domains;
41 21
    }
42
43
    /**
44
     * @return array
45
     */
46 4
    public function toArray()
47
    {
48 4
        return iterator_to_array($this->getIterator());
49
    }
50
51
    /**
52
     * {@inheritdoc}
53
     */
54 1
    public function prefix(string $prefix, callable $handler)
55
    {
56 1
        $this->group(['prefix' => $prefix, ], $handler);
57 1
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62 1
    public function domain($domain, callable $handler)
63
    {
64 1
        $this->group(['domain' => $domain, ], $handler);
65 1
    }
66
67
    /**
68
     * {@inheritdoc}
69
     */
70 1
    public function middleware($middleware, callable $handler)
71
    {
72 1
        $this->group(['middleware' => $middleware, ], $handler);
73 1
    }
74
75
    /**
76
     * {@inheritdoc}
77
     */
78 7
    public function group(array $attributes, callable $handler)
79
    {
80 7
        $prefix = $this->prefix;
81 7
        if (isset($attributes['prefix'])) {
82 5
            $prefix .= "/" . $attributes['prefix'];
83
        }
84 7
        $middlewares = $this->middlewares;
85 7
        if (isset($attributes['middleware'])) {
86 5
            $middlewares = array_merge($middlewares, array_filter((array)$attributes['middleware']));
87
        }
88 7
        if (isset($attributes['middlewares'])) {
89 1
            $middlewares = array_merge($middlewares, array_filter((array)$attributes['middlewares']));
90
        }
91 7
        $domains = $this->domains;
92 7
        if (isset($attributes['domain'])) {
93 5
            $domains = (array) $attributes['domain'];
94
        }
95 7
        if (isset($attributes['domains'])) {
96 2
            $domains = (array) $attributes['domains'];
97
        }
98 7
        $router = new RouteCollection($prefix, $middlewares, $domains);
99 7
        call_user_func($handler, $router);
100 7
        $this->routers[] = $router;
101 7
    }
102
103
    /**
104
     * {@inheritdoc}
105
     */
106
    public function append(callable $handler)
107
    {
108
        call_user_func($handler, $this);
109
    }
110
111
    public function resource($className, $except = [], $only = [])
0 ignored issues
show
Unused Code introduced by
The parameter $except is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $only is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
112
    {
113
        $this->get('', $className, 'index');
114
        $this->post('', $className, 'store');
115
        $this->get(':id', $className, 'show');
116
        $this->put(':id', $className, 'update');
117
        $this->patch(':id', $className, 'patch');
118
        $this->delete(':id', $className, 'destroy');
119
        // $this->options();
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125 12
    public function get(string $path, string $className, string $methodName = 'index'): RouteFluent
126
    {
127 12
        return $this->createRoute(['GET', 'HEAD'], $path, $className, $methodName);
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133 6
    public function post(string $path, string $className, string $methodName = 'index'): RouteFluent
134
    {
135 6
        return $this->createRoute(['POST'], $path, $className, $methodName);
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141 1
    public function put(string $path, string $className, string $methodName = 'index'): RouteFluent
142
    {
143 1
        return $this->createRoute(['PUT'], $path, $className, $methodName);
144
    }
145
146
    /**
147
     * {@inheritdoc}
148
     */
149 1
    public function delete(string $path, string $className, string $methodName = 'index'): RouteFluent
150
    {
151 1
        return $this->createRoute(['DELETE'], $path, $className, $methodName);
152
    }
153
154
    /**
155
     * {@inheritdoc}
156
     */
157 1
    public function options(string $path, string $className, string $methodName = 'index'): RouteFluent
158
    {
159 1
        return $this->createRoute(['OPTIONS'], $path, $className, $methodName);
160
    }
161
162
    /**
163
     * {@inheritdoc}
164
     */
165 1
    public function patch(string $path, string $className, string $methodName = 'index'): RouteFluent
166
    {
167 1
        return $this->createRoute(['PATCH'], $path, $className, $methodName);
168
    }
169
170
    /**
171
     * {@inheritdoc}
172
     */
173 3
    public function any(string $path, string $className, string $methodName = 'index'): RouteFluent
174
    {
175 3
        return $this->createRoute([
176 3
            'GET',
177
            'HEAD',
178
            'POST',
179
            'PUT',
180
            'DELETE',
181
            'OPTIONS',
182
            'PATCH'
183 3
        ], $path, $className, $methodName);
184
    }
185
186
    /**
187
     * {@inheritdoc}
188
     */
189 21
    public function createRoute(array $methods, string $path, string $className, string $methodName = 'index'): RouteFluent
190
    {
191 21
        $path = trim("{$this->prefix}/{$path}", '/');
192 21
        while(strpos($path, '//') !== false) {
193 2
            $path = str_replace('//', '/', $path);
194
        }
195 21
        $path = '/' . $path;
196 21
        $route = new Route($className, $methodName, $this->middlewares, $this->domains);
197 21
        $this->routes[] = [$methods, $path, $route];
198 21
        return $route;
199
    }
200
201
    /**
202
     * {@inheritdoc}
203
     */
204 19
    public function getIterator()
205
    {
206 19
        foreach ($this->routes as $route) {
207 19
            yield $route;
208
        }
209 19
        foreach ($this->routers as $router) {
210 5
            foreach ($router as $route) {
211 5
                yield $route;
212
            }
213
        }
214 19
    }
215
216
    /**
217
     * {@inheritdoc}
218
     */
219 15
    public function dispatch(LoaderInterface $loader, ResponsifierInterface $responsifier, ServerRequestInterface $request)
220
    {
221 15
        return $this->compile()->dispatch($loader, $responsifier, $request);
222
    }
223
224
    /**
225
     * @return \Wandu\Router\CompiledRouteCollection
226
     */
227 15
    public function compile(): CompiledRouteCollection
228
    {
229 15
        $routeMap = [];
230
231
        /** @var \FastRoute\DataGenerator\GroupCountBased[] $generators */
232
        $generators = [
233 15
            '@' => new GCBGenerator(),
234
        ];
235
236
        /**
237
         * @var array|string[] $methods
238
         * @var string $path
239
         * @var \Wandu\Router\Route $route
240
         */
241 15
        foreach ($this->getIterator() as list($methods, $path, $route)) {
242 15
            $pathPattern = new Pattern($path);
243
244 15
            $handleId = uniqid('HANDLER');
245 15
            $routeMap[$handleId] = $route;
246
247 15
            foreach ($pathPattern->parse() as $parsedPath) {
248 15
                foreach ($methods as $method) {
249 15
                    $domains = $route->getDomains();
250 15
                    if (count($domains)) {
251 2
                        foreach ($domains as $domain) {
252 2
                            if (!isset($generators[$domain])) {
253 2
                                $generators[$domain] = new GCBGenerator();
254
                            }
255 2
                            $generators[$domain]->addRoute($method, $parsedPath, $handleId);
256
                        }
257
                    } else {
258 15
                        $generators['@']->addRoute($method, $parsedPath, $handleId);
259
                    }
260
                }
261
            }
262
        }
263
264 15
        $compiledRoutes = array_map(function (GCBGenerator $generator) {
265 15
            return $generator->getData();
266 15
        }, $generators);
267 15
        return new CompiledRouteCollection($compiledRoutes, $routeMap);
268
    }
269
}
270