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

GroupingTrait::loadAnnotation()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
c 3
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\Route;
22
use Flight\Routing\Interfaces\RouteCompilerInterface;
23
24
trait GroupingTrait
25
{
26
    /** @var self|null */
27
    private $parent = null;
28
29
    /** @var array<string,mixed[]>|null */
30
    private $stack = null;
31
32
    /** @var int */
33
    private $countRoutes = 0;
34
35
    /** @var RouteCompilerInterface */
36
    private $compiler;
37
38
    /**
39
     * Load routes from annotation.
40
     */
41
    public function loadAnnotation(LoaderInterface $loader): void
42
    {
43
        $annotations = $loader->load();
44
45
        foreach ($annotations as $annotation) {
46
            if ($annotation instanceof self) {
47
                $this['group'][] = $annotation;
48
            }
49
        }
50
    }
51
52
    /**
53
     * Bind route with collection.
54
     */
55
    private function resolveWith(Route $route): Route
56
    {
57
        if (null !== $stack = $this->stack) {
58
            foreach ($stack as $routeMethod => $arguments) {
59
                if (empty($arguments)) {
60
                    continue;
61
                }
62
63
                \call_user_func_array([$route, $routeMethod], 'prefix' === $routeMethod ? [\implode('', $arguments)] : $arguments);
64
            }
65
        }
66
67
        if (null === $this->parent) {
68
            $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

68
            $this->processRouteMaps($route, $this->countRoutes, /** @scrutinizer ignore-type */ $this);
Loading history...
69
        } else {
70
            $route->belong($this); // Attach grouping to route.
71
        }
72
73
        ++$this->countRoutes;
74
75
        return $route;
76
    }
77
78
    /**
79
     * @param \ArrayIterator<string,mixed> $routes
80
     *
81
     * @return array<int,Route>
82
     */
83
    private function doMerge(string $prefix, self $routes): void
84
    {
85
        $unnamedRoutes = [];
86
87
        /** @var \ArrayIterator<string,mixed>|self $group */
88
        foreach ($this['group'] ?? [] as $namePrefix => $group) {
89
            $namedGroup = \is_string($namePrefix) ? $namePrefix : '';
90
91
            /** @var Route $route */
92
            foreach ($group['routes'] ?? [] as $route) {
93
                $routes['routes'][] = $route->bind($this->generateRouteName($route, $prefix . $namedGroup, $unnamedRoutes));
94
                $this->processRouteMaps($route, $routes->countRoutes, $routes);
95
96
                ++$routes->countRoutes;
97
            }
98
99
            if ($group->offsetExists('group')) {
100
                $group->doMerge($prefix . $namedGroup, $routes);
101
            }
102
        }
103
    }
104
105
    /**
106
     * @param \ArrayIterator|array $routes
107
     */
108
    private function processRouteMaps(Route $route, int $routeId, \ArrayIterator $routes): void
109
    {
110
        [$pathRegex, $hostsRegex, $variables] = $this->compiler->compile($route);
111
112
        if ('\\' === $pathRegex[0]) {
113
            $routes['dynamicRoutesMap'][0][] = \preg_replace('/\?(?|P<\w+>|<\w+>|\'\w+\')/', '', (empty($hostsRegex) ? '(?:\\/{2}[^\/]+)?' : '\\/{2}(?i:(?|' . \implode('|', $hostsRegex) . '))') . $pathRegex) . '(*:' . $routeId . ')';
114
            $routes['dynamicRoutesMap'][1][$routeId] = $variables;
115
        } else {
116
            $routes['staticRoutesMap'][$pathRegex] = [$routeId, !empty($hostsRegex) ? '#^(?|' . \implode('|', $hostsRegex) . ')$#i' : null, $variables];
117
        }
118
    }
119
120
    private function generateRouteName(Route $route, string $prefix, array $unnamedRoutes): string
121
    {
122
        if (null === $name = $route->get('name')) {
123
            $name = $route->generateRouteName('');
124
125
            if (isset($unnamedRoutes[$name])) {
126
                $name .= ('_' !== $name[-1] ? '_' : '') . ++$unnamedRoutes[$name];
127
            } else {
128
                $unnamedRoutes[$name] = 0;
129
            }
130
        }
131
132
        return $prefix . $name;
133
    }
134
}
135