Passed
Push — master ( 70c68f...c76078 )
by Alexander
06:58
created

RouteCollection::injectGroup()   B

Complexity

Conditions 7
Paths 11

Size

Total Lines 36
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 8.5786

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 22
c 1
b 0
f 0
dl 0
loc 36
ccs 15
cts 22
cp 0.6818
rs 8.6346
cc 7
nc 11
nop 3
crap 8.5786
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Router;
6
7
use InvalidArgumentException;
8
9
final class RouteCollection implements RouteCollectionInterface
10
{
11
    /**
12
     * @var array
13
     */
14
    private array $items = [];
15
16
    /**
17
     * All attached routes as Route instances
18
     *
19
     * @var Route[]
20
     */
21
    private array $routes = [];
22
23
    /**
24
     * RouteCollection constructor.
25
     * @param RouteCollectorInterface $collector
26
     * @param string $prefix
27
     * @param bool $buildRoutes
28
     */
29 3
    public function __construct(RouteCollectorInterface $collector)
30
    {
31 3
        $this->injectItems([$collector]);
32
    }
33
34
    /**
35
     * @return Route[]
36
     */
37
    public function getRoutes(): array
38
    {
39
        return $this->routes;
40
    }
41
42
    /**
43
     * @param string $name
44
     * @return Route
45
     */
46 2
    public function getRoute(string $name): Route
47
    {
48 2
        if (!array_key_exists($name, $this->routes)) {
49
            throw new RouteNotFoundException($name);
50
        }
51
52 2
        return $this->routes[$name];
53
    }
54
55
    /**
56
     * Returns routes tree array
57
     *
58
     * @param bool $routeAsString
59
     * @return array
60
     */
61
    public function getRouteTree(bool $routeAsString = true): array
62
    {
63
        return $this->buildTree($this->items, $routeAsString);
64
    }
65
66
    /**
67
     * Build routes array
68
     *
69
     * @param Route[]|Group[]|RouteCollectorInterface[] $items
70
     */
71 3
    private function injectItems(array $items): void
72
    {
73 3
        foreach ($items as $index => $item) {
74 3
            $this->injectItem($item);
75
        }
76
    }
77
78
    /**
79
     * Add an item into routes array
80
     * @param Route|Group $route
81
     */
82 3
    private function injectItem($route): void
83
    {
84 3
        if ($route instanceof Group) {
85 3
            $this->injectGroup($route, $this->items);
86 2
            return;
87
        }
88
89
        $this->items[] = $route->getName();
90
        $this->routes[$route->getName()] = $route;
91
    }
92
93
    /**
94
     * Inject a Group instance into route and item arrays.
95
     */
96 3
    private function injectGroup(Group $group, array &$tree, string $prefix = ''): void
97
    {
98 3
        $prefix .= $group->getPrefix();
99
        /** @var $items Group[]|Route[] */
100 3
        $items = $group->getItems();
101 3
        foreach ($items as $index => $item) {
102 3
            if ($item instanceof Group) {
103
                if (empty($item->getPrefix())) {
104
                    $this->injectGroup($item, $tree, $prefix);
105
                    continue;
106
                }
107
                $tree[$item->getPrefix()] = [];
108
                $this->injectGroup($item, $tree[$item->getPrefix()], $prefix);
109
                continue;
110
            }
111
112 3
            if (empty($tree[$group->getPrefix()])) {
113 3
                $tree[] = $item->getName();
114
            } else {
115
                $tree[$group->getPrefix()][] = $item->getName();
116
            }
117
118
            /** @var Route $modifiedItem */
119 3
            $modifiedItem = $item->pattern($prefix . $item->getPattern());
120
121 3
            $groupMiddlewares = $group->getMiddlewares();
122
123 3
            for (end($groupMiddlewares); key($groupMiddlewares) !== null; prev($groupMiddlewares)) {
124 2
                $modifiedItem = $modifiedItem->addMiddleware(current($groupMiddlewares));
125
            }
126
127 3
            $routeName = $modifiedItem->getName();
128 3
            if (isset($this->routes[$routeName])) {
129 1
                throw new InvalidArgumentException("A route with name '$routeName' already exists.");
130
            }
131 3
            $this->routes[$routeName] = $modifiedItem;
132
        }
133
    }
134
135
    /**
136
     * Builds route tree from items
137
     *
138
     * @param array $items
139
     * @param bool $routeAsString
140
     * @return array
141
     */
142
    private function buildTree(array $items, bool $routeAsString): array
143
    {
144
        $tree = [];
145
        foreach ($items as $key => $item) {
146
            if (is_array($item)) {
147
                $tree[$key] = $this->buildTree($items[$key], $routeAsString);
148
            } else {
149
                $tree[] = $routeAsString ? (string)$this->getRoute($item) : $this->getRoute($item);
150
            }
151
        }
152
        return $tree;
153
    }
154
}
155