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

GroupingTrait::doMerge()   A

Complexity

Conditions 6
Paths 18

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
cc 6
eloc 11
c 6
b 0
f 0
nc 18
nop 3
dl 0
loc 21
rs 9.2222
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, bool $merge = true): void
84
    {
85
        $unnamedRoutes = [];
86
87
        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

87
        foreach ($this->/** @scrutinizer ignore-call */ offsetGet('group') as $namePrefix => $group) {
Loading history...
88
            $prefix .= \is_string($namePrefix) ? $namePrefix : '';
89
90
            foreach ($group['routes'] ?? [] as $route) {
91
                $routes['routes'][] = $route->bind($this->generateRouteName($route, $prefix, $unnamedRoutes));
92
                $this->processRouteMaps($route, $routes->countRoutes, $routes);
93
94
                ++$routes->countRoutes;
95
            }
96
97
            if ($group->offsetExists('group')) {
98
                $group->doMerge($prefix, $routes, false);
99
            }
100
        }
101
102
        if ($merge) {
103
            $routes->offsetUnset('group'); // Unset grouping ...
104
        }
105
    }
106
107
    /**
108
     * @param \ArrayIterator|array $routes
109
     */
110
    private function processRouteMaps(Route $route, int $routeId, \ArrayIterator $routes): void
111
    {
112
        [$pathRegex, $hostsRegex, $variables] = $this->compiler->compile($route);
113
114
        if ('\\' === $pathRegex[0]) {
115
            $routes['dynamicRoutesMap'][0][] = \preg_replace('/\?(?|P<\w+>|<\w+>|\'\w+\')/', '', (empty($hostsRegex) ? '(?:\\/{2}[^\/]+)?' : '\\/{2}(?i:(?|' . \implode('|', $hostsRegex) . '))') . $pathRegex) . '(*:' . $routeId . ')';
116
            $routes['dynamicRoutesMap'][1][$routeId] = $variables;
117
118
            if (!isset($routes['dynamicRoutesMap'][2])) {
119
                $routes['dynamicRoutesMap'][2] = true; // needs dynamic routes to compile.
120
            }
121
        } else {
122
            $routes['staticRoutesMap'][$pathRegex] = [$routeId, !empty($hostsRegex) ? '#^(?|' . \implode('|', $hostsRegex) . ')$#i' : null, $variables];
123
        }
124
    }
125
126
    private function generateRouteName(Route $route, string $prefix, array $unnamedRoutes): string
127
    {
128
        if (null === $name = $route->get('name')) {
129
            $name = $route->generateRouteName('');
130
131
            if (isset($unnamedRoutes[$name])) {
132
                $name .= ('_' !== $name[-1] ? '_' : '') . ++$unnamedRoutes[$name];
133
            } else {
134
                $unnamedRoutes[$name] = 0;
135
            }
136
        }
137
138
        return $prefix . $name;
139
    }
140
}
141