Passed
Pull Request — master (#68)
by Dmitriy
14:50
created

Group::create()   A

Complexity

Conditions 6
Paths 3

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6.1308

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 14
c 1
b 0
f 0
nc 3
nop 3
dl 0
loc 21
ccs 11
cts 13
cp 0.8462
crap 6.1308
rs 9.2222
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Router;
6
7
use InvalidArgumentException;
8
use Psr\Http\Server\MiddlewareInterface;
9
10
final class Group implements RouteCollectorInterface
11
{
12
    /**
13
     * @var Group[]|Route[]
14
     */
15
    protected array $items = [];
16
    protected ?string $prefix;
17
    protected array $middlewares = [];
18
    private ?DispatcherInterface $dispatcher = null;
19
20
    private function __construct(?string $prefix = null, ?callable $callback = null, DispatcherInterface $dispatcher = null)
21 10
    {
22
        $this->dispatcher = $dispatcher;
23 10
        $this->prefix = $prefix;
24 10
25
        if ($callback !== null) {
26 10
            $callback($this);
27 10
        }
28
    }
29 10
30
    /**
31
     * Create a new instance
32
     *
33
     * @param string|null $prefix
34
     * @param callable|array $routes
35
     * @param DispatcherInterface $dispatcher
36
     *
37
     * @return self
38
     */
39
    public static function create(?string $prefix = null, $routes = [], DispatcherInterface $dispatcher = null): self
40 10
    {
41
        if (\is_callable($routes)) {
42 10
            $callback = $routes;
43 4
        } elseif (is_array($routes)) {
44 9
            $callback = static function (Group $group) use (&$routes) {
45 9
                foreach ($routes as $route) {
46 9
                    if ($route instanceof Route) {
47 3
                        $group->addRoute($route);
48 3
                    } elseif ($route instanceof Group) {
49 3
                        $group->addGroup($route);
50 3
                    } else {
51
                        throw new InvalidArgumentException('Route should be either instance of Route or Group.');
52
                    }
53
                }
54
            };
55 9
        } else {
56
            $callback = null;
57
        }
58
59
        return new self($prefix, $callback, $dispatcher);
60 10
    }
61
62
    public function injectDispatcher(DispatcherInterface $dispatcher): void
63 3
    {
64
        $this->dispatcher = $dispatcher;
65 3
        foreach ($this->items as $index => $item) {
66 3
            if (!$item->hasDispatcher()) {
67 3
                $item->injectDispatcher($dispatcher);
68 3
                $this->items[$index] = $item;
69 3
            }
70 3
        }
71
    }
72
73
    public function hasDispatcher(): bool
74 3
    {
75
        return $this->dispatcher !== null;
76
    }
77 9
78
    public function addRoute(Route $route): self
79 9
    {
80
        if (!$route->hasDispatcher() && $this->hasDispatcher()) {
81
            $route->injectDispatcher($this->dispatcher);
82 9
        }
83
        $this->items[] = $route;
84 9
        return $this;
85 4
    }
86
87 9
    public function addGroup(Group $group): self
88 9
    {
89
        if (!$group->hasDispatcher() && $this->hasDispatcher()) {
90
            $group->injectDispatcher($this->dispatcher);
91 7
        }
92
        $this->items[] = $group;
93 7
        return $this;
94 3
    }
95
96 7
    /**
97 7
     * @param MiddlewareInterface|callable|string|array $middleware
98
     */
99
    private function validateMiddleware($middleware): void
100
    {
101
        if (
102
            is_string($middleware) && is_subclass_of($middleware, MiddlewareInterface::class)
103 6
        ) {
104
            return;
105
        }
106 6
107
        if ($this->isCallable($middleware) && (!is_array($middleware) || !is_object($middleware[0]))) {
108
            return;
109
        }
110
111 6
        throw new InvalidArgumentException('Parameter should be either PSR middleware class name or a callable.');
112 6
    }
113
114
    private function isCallable($definition): bool
115
    {
116
        if (is_callable($definition)) {
117
            return true;
118 6
        }
119
120 6
        return is_array($definition) && array_keys($definition) === [0, 1] && in_array($definition[1], get_class_methods($definition[0]) ?? [], true);
121 6
    }
122
123
    /**
124
     * @param callable|MiddlewareInterface $middleware
125
     * @return $this
126
     */
127
    public function addMiddleware($middleware): self
128
    {
129
        $this->validateMiddleware($middleware);
130
        $this->middlewares[] = $middleware;
131 6
132
        return $this;
133 6
    }
134 6
135
    /**
136 6
     * @return Route|Group[]
137
     */
138
    public function getItems(): array
139
    {
140
        return $this->items;
141
    }
142 9
143
    public function getPrefix(): ?string
144 9
    {
145
        return $this->prefix;
146
    }
147 5
148
    public function getMiddlewares(): array
149 5
    {
150
        return $this->middlewares;
151
    }
152
}
153