Passed
Push — master ( 8844b9...9328af )
by Alexander
02:49 queued 01:34
created

RouteCollection::injectGroup()   B

Complexity

Conditions 7
Paths 13

Size

Total Lines 35
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 7.2944

Importance

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