Passed
Push — master ( b6349f...08228d )
by Alexander
01:17
created

RouteCollection::ensureItemsInjected()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

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