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

MiddlewareFactory::create()   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 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
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
use Psr\Container\ContainerInterface;
9
use Psr\Http\Message\ResponseInterface;
10
use Psr\Http\Message\ServerRequestInterface;
11
use Psr\Http\Server\MiddlewareInterface;
12
use Psr\Http\Server\RequestHandlerInterface;
13
use Yiisoft\Injector\Injector;
14
15
final class MiddlewareFactory implements MiddlewareFactoryInterface
16
{
17
    private ContainerInterface $container;
18
19 23
    public function __construct(ContainerInterface $container)
20
    {
21 23
        $this->container = $container;
22 23
    }
23
24 20
    public function create($middlewareDefinition): MiddlewareInterface
25
    {
26 20
        return $this->createMiddleware($middlewareDefinition);
27
    }
28
29
    /**
30
     * @param callable|string|array $middlewareDefinition
31
     * @return MiddlewareInterface
32
     */
33 20
    private function createMiddleware($middlewareDefinition): MiddlewareInterface
34
    {
35 20
        $this->validateMiddleware($middlewareDefinition);
36
37 14
        if (is_string($middlewareDefinition)) {
38 1
            return $this->container->get($middlewareDefinition);
39
        }
40
41 13
        if (is_array($middlewareDefinition) && !is_object($middlewareDefinition[0])) {
42 4
            return $this->wrapCallable($middlewareDefinition);
43
        }
44
45 9
        if ($this->isCallable($middlewareDefinition)) {
46 9
            return $this->wrapCallable($middlewareDefinition);
47
        }
48
49
        throw new \RuntimeException('Middleware creating error.');
50
    }
51
52 13
    private function wrapCallable($callback): MiddlewareInterface
53
    {
54 13
        if (is_array($callback) && !is_object($callback[0])) {
55 4
            [$controller, $action] = $callback;
56 4
            return new class($controller, $action, $this->container) implements MiddlewareInterface {
57
                private string $class;
58
                private string $method;
59
                private ContainerInterface $container;
60
61
                public function __construct(string $class, string $method, ContainerInterface $container)
62
                {
63 4
                    $this->class = $class;
64 4
                    $this->method = $method;
65 4
                    $this->container = $container;
66 4
                }
67
68
                public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
69
                {
70 3
                    $controller = $this->container->get($this->class);
71 3
                    return (new Injector($this->container))->invoke([$controller, $this->method], [$request, $handler]);
72
                }
73
            };
74
        }
75
76 9
        return new class($callback, $this->container) implements MiddlewareInterface {
77
            private ContainerInterface $container;
78
            private $callback;
79
80
            public function __construct(callable $callback, ContainerInterface $container)
81
            {
82 9
                $this->callback = $callback;
83 9
                $this->container = $container;
84 9
            }
85
86
            public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
87
            {
88 9
                $response = (new Injector($this->container))->invoke($this->callback, [$request, $handler]);
89 9
                return $response instanceof MiddlewareInterface ? $response->process($request, $handler) : $response;
90
            }
91
        };
92
    }
93
94
    /**
95
     * @param callable|string|array $middlewareDefinition
96
     */
97 20
    private function validateMiddleware($middlewareDefinition): void
98
    {
99
        if (
100 20
            is_string($middlewareDefinition) && is_subclass_of($middlewareDefinition, MiddlewareInterface::class)
101
        ) {
102 1
            return;
103
        }
104
105 19
        if ($this->isCallable($middlewareDefinition) && (!is_array($middlewareDefinition) || !is_object($middlewareDefinition[0]))) {
106 13
            return;
107
        }
108
109 6
        throw new InvalidArgumentException('Parameter should be either PSR middleware class name or a callable.');
110
    }
111
112 19
    private function isCallable($definition): bool
113
    {
114 19
        if (is_callable($definition)) {
115 13
            return true;
116
        }
117
118 6
        return is_array($definition)
119 6
            && array_keys($definition) === [0, 1]
120 1
            && in_array(
121 1
                $definition[1],
122 1
                class_exists($definition[0]) ? get_class_methods($definition[0]) : [],
123 6
                true
124
            );
125
    }
126
}
127