Test Failed
Pull Request — master (#16)
by Divine Niiquaye
02:33
created

GroupingTrait::loadAnnotation()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
c 2
b 0
f 0
nc 3
nop 1
dl 0
loc 7
rs 10
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, Route};
22
use Flight\Routing\Interfaces\RouteCompilerInterface;
23
24
trait GroupingTrait
25
{
26
    /** @var array */
27
    private $cacheData = null;
28
29
    /** @var self|null */
30
    private $parent = null;
31
32
    /** @var array<string,mixed[]>|null */
33
    private $stack = null;
34
35
    /** @var int */
36
    private $countRoutes = 0;
37
38
    /** @var DebugRoute|null */
39
    private $profiler = null;
40
41
    /** @var RouteCompilerInterface */
42
    private $compiler;
43
44
    /**
45
     * If routes was debugged, return the profiler.
46
     */
47
    public function getDebugRoute(): ?DebugRoute
48
    {
49
        return $this->profiler;
50
    }
51
52
    /**
53
     * Load routes from annotation.
54
     */
55
    public function loadAnnotation(LoaderInterface $loader): void
56
    {
57
        $annotations = $loader->load();
58
59
        foreach ($annotations as $annotation) {
60
            if ($annotation instanceof self) {
61
                $this['group'][] = $annotation;
62
            }
63
        }
64
    }
65
66
    /**
67
     * Bind route with collection.
68
     */
69
    private function resolveWith(Route $route): Route
70
    {
71
        if (null !== $stack = $this->stack) {
72
            foreach ($stack as $routeMethod => $arguments) {
73
                if (empty($arguments)) {
74
                    continue;
75
                }
76
77
                \call_user_func_array([$route, $routeMethod], 'prefix' === $routeMethod ? [\implode('', $arguments)] : $arguments);
78
            }
79
        }
80
81
        if (null === $this->parent) {
82
            $this->processRouteMaps($route, $this->countRoutes, $this);
0 ignored issues
show
Bug introduced by
$this of type Flight\Routing\Traits\GroupingTrait is incompatible with the type ArrayIterator expected by parameter $routes of Flight\Routing\Traits\Gr...ait::processRouteMaps(). ( Ignorable by Annotation )

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

82
            $this->processRouteMaps($route, $this->countRoutes, /** @scrutinizer ignore-type */ $this);
Loading history...
83
84
            if (null !== $this->profiler) {
85
                $this->profiler->addProfile($route);
86
            }
87
        } else {
88
            $route->belong($this); // Attach grouping to route.
89
        }
90
91
        ++$this->countRoutes;
92
93
        return $route;
94
    }
95
96
    /**
97
     * @param \ArrayIterator<string,mixed> $routes
98
     *
99
     * @return array<int,Route>
100
     */
101
    private function doMerge(string $prefix, self $routes, bool $merge = true): void
102
    {
103
        $unnamedRoutes = [];
104
105
        foreach ($this->offsetGet('group') as $namePrefix => $group) {
0 ignored issues
show
Bug introduced by
It seems like offsetGet() 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

105
        foreach ($this->/** @scrutinizer ignore-call */ offsetGet('group') as $namePrefix => $group) {
Loading history...
106
            $prefix .= \is_string($namePrefix) ? $namePrefix : '';
107
108
            foreach ($group['routes'] ?? [] as $route) {
109
                if (null === $name = $route->get('name')) {
110
                    $name = $route->generateRouteName('');
111
112
                    if (isset($unnamedRoutes[$name])) {
113
                        $name .= ('_' !== $name[-1] ? '_' : '') . ++$unnamedRoutes[$name];
114
                    } else {
115
                        $unnamedRoutes[$name] = 0;
116
                    }
117
                }
118
119
                $routes['routes'][] = $route->bind($prefix . $name);
120
121
                if (null !== $routes->profiler) {
122
                    $routes->profiler->addProfile($route);
123
                }
124
125
                $this->processRouteMaps($route, $routes->countRoutes, $routes);
126
127
                ++$routes->countRoutes;
128
            }
129
130
            if ($group->offsetExists('group')) {
131
                $group->doMerge($prefix, $routes, false);
132
            }
133
        }
134
135
        if ($merge) {
136
            $routes->offsetUnset('group'); // Unset grouping ...
137
        }
138
    }
139
140
    /**
141
     * @param \ArrayIterator|array $routes
142
     */
143
    private function processRouteMaps(Route $route, int $routeId, \ArrayIterator $routes): void
144
    {
145
        [$pathRegex, $hostsRegex, $variables] = $this->compiler->compile($route);
146
147
        if ('\\' === $pathRegex[0]) {
148
            $routes['dynamicRoutesMap'][0][] = \preg_replace('/\?(?|P<\w+>|<\w+>|\'\w+\')/', '', (empty($hostsRegex) ? '(?:\\/{2}[^\/]+)?' : '\\/{2}(?i:(?|' . \implode('|', $hostsRegex) . '))') . $pathRegex) . '(*:' . $routeId . ')';
149
            $routes['dynamicRoutesMap'][1][$routeId] = $variables;
150
        } else {
151
            $routes['staticRoutesMap'][$pathRegex] = [$routeId, !empty($hostsRegex) ? '#^(?|' . \implode('|', $hostsRegex) . ')$#i' : null, $variables];
152
        }
153
    }
154
155
    private function generateRouteName(Route $route, array $unnamedRoutes): string
156
    {
157
        if (null === $name = $route->get('name')) {
158
            $name = $route->generateRouteName('');
159
160
            if (isset($unnamedRoutes[$name])) {
161
                $name .= ('_' !== $name[-1] ? '_' : '') . ++$unnamedRoutes[$name];
162
            } else {
163
                $unnamedRoutes[$name] = 0;
164
            }
165
        }
166
167
        return $name;
168
    }
169
}
170