Passed
Push — master ( 1da3d9...4f22f8 )
by Alexander
23:29 queued 21:59
created

Group::addMiddleware()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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