Passed
Pull Request — master (#115)
by Rustam
02:17
created

RouteCollection::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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