Test Failed
Pull Request — master (#13)
by Divine Niiquaye
14:05
created

RouterTrait   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 189
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
wmc 30
eloc 54
c 6
b 0
f 0
dl 0
loc 189
rs 10
ccs 52
cts 52
cp 1

10 Methods

Rating   Name   Duplication   Size   Complexity  
A getProfile() 0 3 1
A setProfile() 0 3 1
A getRoute() 0 10 2
A getAllowedMethods() 0 11 3
A loadAnnotation() 0 5 3
A mergeAttributes() 0 15 6
A addParameters() 0 8 4
B mergeDefaults() 0 20 7
A addRouteListener() 0 4 2
A setNamespace() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Flight Routing.
7
 *
8
 * PHP version 7.1 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 Biurad Group (https://biurad.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Flight\Routing\Traits;
19
20
use Biurad\Annotations\LoaderInterface;
21
use Flight\Routing\DebugRoute;
22
use Flight\Routing\Exceptions\RouteNotFoundException;
23
use Flight\Routing\Interfaces\RouteListenerInterface;
24
use Flight\Routing\Interfaces\RouteMatcherInterface;
25
use Flight\Routing\Route;
26
use Flight\Routing\RouteCollection;
27
use Flight\Routing\Router;
28
use Psr\Http\Message\ResponseFactoryInterface;
29
use Psr\Http\Message\UriFactoryInterface;
30
31
trait RouterTrait
32
{
33
    use ResolveTrait;
34
    use DumperTrait;
35
36
    /** @var null|RouteMatcherInterface */
37
    private $matcher;
38
39
    /** @var ResponseFactoryInterface */
40
    private $responseFactory;
41
42
    /** @var UriFactoryInterface */
43
    private $uriFactory;
44
45
    /** @var null|DebugRoute */
46
    private $debug;
47
48
    /** @var RouteCollection */
49
    private $routes;
50
51
    /** @var RouteCollectionenerInterface[] */
52
    private $listeners = [];
53
54
    /** @var array<int,mixed> */
55
    private $attributes = [];
56
57
    /**
58
     * Gets allowed methods
59
     *
60
     * @return string[]
61
     */
62 1
    public function getAllowedMethods(): array
63
    {
64 1
        $methods = [];
65
66 1
        foreach ($this->getCollection()->getRoutes() as $route) {
0 ignored issues
show
Bug introduced by
It seems like getCollection() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

66
        foreach ($this->/** @scrutinizer ignore-call */ getCollection()->getRoutes() as $route) {
Loading history...
67 1
            foreach ($route->getMethods() as $method => $has) {
68 1
                $methods[$method] = $has;
69
            }
70
        }
71
72 1
        return \array_keys($methods);
73
    }
74
75
    /**
76
     * Gets a route for the given name
77
     *
78
     * @param string $name
79
     *
80
     * @throws RouteNotFoundException
81
     *
82
     * @return Route
83
     */
84 6
    public function getRoute(string $name): Route
85
    {
86 6
        // To Allow merging incase routes after this method doesn't exist
87 2
        $this->routes->getRoutes();
88
89
        if (null !== $this->routes->find($name)) {
90 4
            return $this->routes->find($name);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->routes->find($name) could return the type null which is incompatible with the type-hinted return Flight\Routing\Route. Consider adding an additional type-check to rule them out.
Loading history...
91
        }
92
93
        throw new RouteNotFoundException(\sprintf('No route found for the name "%s".', $name));
94
    }
95
96
    /**
97
     * Get the profiled routes
98 1
     *
99
     * @return null|DebugRoute
100 1
     */
101
    public function getProfile(): ?DebugRoute
102
    {
103
        return $this->debug;
104
    }
105
106 1
    /**
107
     * Set profiling for routes
108 1
     */
109 1
    public function setProfile(): void
110
    {
111
        $this->debug = new DebugRoute();
112
    }
113
114
    /**
115
     * Set Namespace for route handlers/controllers
116 4
     *
117
     * @param string $namespace
118 4
     */
119 4
    public function setNamespace(string $namespace): void
120
    {
121
        $this->namespace = \rtrim($namespace, '\\/') . '\\';
122
    }
123
124
    /**
125
     * Adds parameters.
126
     *
127
     * This method implements a fluent interface.
128
     *
129 5
     * @param array<string,mixed> $parameters The parameters
130
     * @param int                 $type
131 5
     */
132 5
    public function addParameters(array $parameters, int $type = Router::TYPE_REQUIREMENT): void
133 3
    {
134
        if (Router::TYPE_DEFAULT === $type) {
135 3
            $this->attributes[Router::TYPE_DEFAULT] = $parameters;
136 5
        } elseif (Router::TYPE_CACHE === $type) {
137 2
            $this->attributes[Router::TYPE_CACHE] = \current($parameters);
138
        } elseif (Router::TYPE_REQUIREMENT === $type) {
139 2
            $this->attributes[Router::TYPE_REQUIREMENT] = $parameters;
140
        }
141
    }
142 3
143
    /**
144 5
     * Adds the given route(s) listener to the router
145
     *
146
     * @param RouteListenerInterface ...$listeners
147
     */
148
    public function addRouteListener(RouteListenerInterface ...$listeners): void
149
    {
150
        foreach ($listeners as $listener) {
151 1
            $this->listeners[] = $listener;
152
        }
153 1
    }
154 1
155
    /**
156 1
     * Load routes from annotation.
157
     *
158
     * @param LoaderInterface $loader
159
     */
160
    public function loadAnnotation(LoaderInterface $loader): void
161
    {
162
        foreach ($loader->load() as $annotation) {
163 14
            if ($annotation instanceof RouteCollection) {
164
                $this->addRoute(...$annotation->getRoutes());
0 ignored issues
show
Bug introduced by
The method addRoute() does not exist on Flight\Routing\Traits\RouterTrait. Did you maybe mean addRouteListener()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

164
                $this->/** @scrutinizer ignore-call */ 
165
                       addRoute(...$annotation->getRoutes());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
165 14
            }
166 4
        }
167 4
    }
168
169
    /**
170 4
     * Get merged default parameters.
171
     *
172
     * @param Route $route
173
     */
174
    private function mergeDefaults(Route $route): void
175
    {
176
        $defaults = $route->getDefaults();
177
        $param    = $defaults['_arguments'] ?? [];
178
        $excludes = [
179 43
            '_arguments' => true,
180
            '_compiler' => true,
181 43
            '_domain' => true,
182
        ];
183 43
184 6
        foreach ($defaults as $key => $value) {
185 6
            if (isset($excludes[$key])) {
186
                continue;
187
            }
188
189 43
            if (
190
                (isset($param[$key]) && null === $param[$key]) || 
191
                (!\is_int($key) && null !== $value)
192
            ) {
193
                $route->argument($key, $value);
194
            }
195
        }
196
    }
197
198
    /**
199 62
     * Merge Router attributes in route default and patterns.
200
     *
201 62
     * @param Route $route
202 5
     *
203 2
     * @return Route
204
     */
205
    private function mergeAttributes(Route $route): Route
206 3
    {
207 3
        foreach ($this->attributes as $type => $attributes) {
208
            if (Router::TYPE_DEFAULT === $type) {
209 3
                foreach ($attributes as $variable => $default) {
210
                    $route->default($variable, $default);
211
                }
212 3
            } elseif (Router::TYPE_REQUIREMENT === $type) {
213
                foreach ($attributes as $variable => $regexp) {
214
                    $route->assert($variable, $regexp);
215 62
                }
216
            }
217
        }
218
219
        return $route;
220
    }
221
}
222