Test Failed
Push — master ( d3660e...c7a4a9 )
by Divine Niiquaye
10:08
created

Listener::getDefaultRouteName()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 8
nc 4
nop 1
dl 0
loc 15
ccs 0
cts 0
cp 0
crap 30
rs 9.6111
c 1
b 0
f 0
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\Annotation;
19
20
use Biurad\Annotations\InvalidAnnotationException;
21
use Biurad\Annotations\ListenerInterface;
22
use Flight\Routing\Route as BaseRoute;
23
use Flight\Routing\RouteCollection;
24
use Flight\Routing\Router;
25
26
class Listener implements ListenerInterface
27
{
28
    /** @var RouteCollection */
29
    private $collector;
30
31
    /**
32
     * @param null|RouteCollection $collector
33
     */
34
    public function __construct(?RouteCollection $collector = null)
35
    {
36
        $this->collector = $collector ?? new RouteCollection();
37
    }
38
39 14
    /**
40
     * {@inheritdoc}
41 14
     *
42 14
     * @param array<string,array<string,mixed>> $annotations
43
     */
44
    public function onAnnotation(array $annotations): RouteCollection
45
    {
46
        foreach ($annotations as $class => $collection) {
47
            if (isset($collection['method'])) {
48
                $this->addRouteGroup($collection['class'] ?? [], $collection['method']);
49 4
50
                continue;
51
            }
52 4
53 4
            /** @var Route $annotation */
54 4
            foreach ($collection['class'] ?? [] as $annotation) {
55
                $this->collector->add($this->addRoute($annotation, $class));
56 4
            }
57
        }
58
59 3
        return $this->collector;
60
    }
61 3
62 3
    /**
63
     * {@inheritdoc}
64
     */
65
    public function getArguments(): array
66 4
    {
67
        return [];
68
    }
69
70
    /**
71
     * {@inheritdoc}
72 3
     */
73
    public function getAnnotation(): string
74 3
    {
75
        return 'Flight\Routing\Annotation\Route';
76
    }
77
78
    /**
79
     * Add a route from annotation
80 4
     *
81
     * @param Route           $annotation
82 4
     * @param string|string[] $handler
83
     * @param null|Route      $group
84
     *
85
     * @return BaseRoute
86
     */
87
    protected function addRoute(Route $annotation, $handler, ?Route $group = null): BaseRoute
88
    {
89
        if (null === $path = $annotation->getPath()) {
90
            throw new InvalidAnnotationException('@Route.path must not be left empty.');
91
        }
92
93
        $route   = new BaseRoute($path, '', $handler);
94 4
        $methods = $annotation->getMethods();
95
96 4
        if (null === $name = $annotation->getName()) {
97
            $name = $base = $route->generateRouteName('annotated_');
98
            $i    = 0;
99
100 4
            while ($this->collector->find($name)) {
101 4
                $name = $base . '_' . ++$i;
102 4
            }
103
        }
104 4
105 4
        if (str_starts_with($path, 'api://') && empty($methods)) {
106 4
            $methods = Router::HTTP_METHODS_STANDARD;
107 4
        }
108 4
109
        if (!empty($methods)) {
110 4
            $route->method(...$methods);
111 4
        }
112
113
        $route->bind($name)->scheme(...$annotation->getSchemes())
114 4
            ->middleware(...$annotation->getMiddlewares())
115
            ->defaults($annotation->getDefaults())
116
        ->asserts($annotation->getPatterns());
117
118
        if (null !== $annotation->getDomain()) {
119
            $route->domain($annotation->getDomain());
120
        }
121
122
        if (null !== $group) {
123 4
            $route = $this->mergeGroup($group, $route);
124
        }
125 4
126 4
        return $route;
127 4
    }
128
129
    /**
130 4
     * Add a routes from annotation into group
131
     *
132
     * @param Route[] $grouping
133 3
     * @param mixed[] $methods
134 3
     */
135
    protected function addRouteGroup(array $grouping, array $methods): void
136
    {
137
        if (!empty($grouping)) {
138
            foreach ($grouping as $group) {
139
                $this->mergeAnnotations($methods, $group);
140 4
            }
141
142 4
            return;
143
        }
144 4
145
        $this->mergeAnnotations($methods);
146 4
    }
147 4
148
    /**
149
     * @param mixed[]    $methods
150 4
     * @param null|Route $group
151 4
     */
152
    protected function mergeAnnotations(array $methods, ?Route $group = null): void
153
    {
154
        $routes = [];
155
156
        foreach ($methods as [$method, $annotation]) {
157
            $routes[] = $this->addRoute($annotation, [$method->class, $method->getName()], $group);
158
        }
159 4
160
        $this->collector->add(...$routes);
161 4
    }
162 4
163 4
    /**
164 4
     * @param Route     $group
165 4
     * @param BaseRoute $route
166 4
     *
167 4
     * @return BaseRoute
168 4
     */
169
    protected function mergeGroup(Route $group, BaseRoute $route): BaseRoute
170 4
    {
171
        $route = $route->bind($group->getName() . $route->getName())
172
            ->scheme(...$group->getSchemes())
173
            ->prefix($group->getPath() ?? '')
174
            ->method(...$group->getMethods())
175
            ->middleware(...$group->getMiddlewares())
176
            ->defaults($group->getDefaults())
177
        ->asserts($group->getPatterns());
178
179
        if (null !== $group->getDomain()) {
180 4
            $route->domain($group->getDomain());
181
        }
182 4
183 4
        return $route;
184
    }
185
}
186