Std::resolveMiddleware()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 10
ccs 6
cts 6
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
1
<?php declare(strict_types=1);
2
3
namespace Phact\Router\Invoker;
4
5
use InvalidArgumentException;
6
use Phact\Router\Invoker;
7
use Phact\Router\RouterHandler;
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
14
class Std implements Invoker, HandlerProcessorInterface
15
{
16
    /**
17
     * @var ContainerInterface|null
18
     */
19
    private $container;
20
21 19
    public function __construct(?ContainerInterface $container = null)
22
    {
23 19
        $this->container = $container;
24 19
    }
25
26
    /**
27
     * @inheritDoc
28
     */
29 19
    public function invoke(ServerRequestInterface $request, $handler, array $variables): ResponseInterface
30
    {
31 19
        if ($handler instanceof RequestHandlerInterface) {
32 1
            return $handler->handle($request);
33
        }
34 18
        if ($handler instanceof RouterHandler) {
35 17
            $middlewaresResolved = [];
36 17
            foreach ($handler->getMiddlewares() as $middleware) {
37 6
                $middlewaresResolved[] = $this->resolveMiddleware($middleware);
38
            }
39 16
            $request = $request->withAttribute('router:variables', $variables);
40 16
            if ($handler->getName()) {
41 6
                $request = $request->withAttribute('router:name', $handler->getName());
42
            }
43 16
            $requestHandler = new HandlerProcessorAdapter($this, $handler->getOriginalHandler(), $variables);
44 16
            return (new Next($requestHandler, $middlewaresResolved))->handle($request);
45
        }
46 1
        return $this->processHandler($request, $handler, $variables);
47
    }
48
49
    /**
50
     * @inheritDoc
51
     */
52 15
    public function processHandler(ServerRequestInterface $request, $handler, array $variables): ResponseInterface
53
    {
54 15
        $controller = $this->getCallable($handler);
55 12
        return $controller($request, $variables);
56
    }
57
58
    /**
59
     * Get the controller callable
60
     *
61
     * @param $callable callable|string|array|object
62
     *
63
     * @return callable
64
     */
65 15
    public function getCallable($callable)
66
    {
67 15
        if (is_string($callable)) {
68 3
            $callable = $this->getCallableFromString($callable);
69
        }
70
71 15
        if (is_array($callable)) {
72 6
            $callable = $this->getCallableFromArray($callable);
73
        }
74
75 15
        if (!is_callable($callable)) {
76 3
            throw new InvalidArgumentException('Could not resolve a callable for this route');
77
        }
78
79 12
        return $callable;
80
    }
81
82
    /**
83
     * Get callable from string
84
     *
85
     * @param string $callable
86
     *
87
     * @return callable|object|array|string
88
     */
89 3
    public function getCallableFromString(string $callable)
90
    {
91 3
        if (strpos($callable, '::') !== false) {
92 1
            return explode('::', $callable);
93
        }
94 2
        if (method_exists($callable, '__invoke')) {
95 1
            return $this->resolveClass($callable);
0 ignored issues
show
Bug introduced by
$callable of type object is incompatible with the type string expected by parameter $class of Phact\Router\Invoker\Std::resolveClass(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

95
            return $this->resolveClass(/** @scrutinizer ignore-type */ $callable);
Loading history...
96
        }
97 1
        return $callable;
98
    }
99
100
    /**
101
     * Get callable from string
102
     *
103
     * @param array $callable
104
     *
105
     * @return callable|array
106
     */
107 6
    public function getCallableFromArray(array $callable)
108
    {
109 6
        if (!isset($callable[0])) {
110 1
            return $callable;
111
        }
112 5
        if (is_object($callable[0])) {
113 1
            return [$callable[0], $callable[1]];
114
        }
115 4
        if (is_string($callable[0])) {
116 3
            return [$this->resolveClass($callable[0]), $callable[1]];
117
        }
118 1
        return $callable;
119
    }
120
121
    /**
122
     * Get an object instance from a class name
123
     *
124
     * @param string $class
125
     *
126
     * @return object
127
     */
128 4
    protected function resolveClass(string $class)
129
    {
130 4
        if ($this->container instanceof ContainerInterface && $this->container->has($class)) {
131 1
            return $this->container->get($class);
132
        }
133
134 3
        return new $class();
135
    }
136
137
    /**
138
     * Resolve a middleware implementation, optionally from a container
139
     *
140
     * @param MiddlewareInterface|string $middleware
141
     *
142
     * @return MiddlewareInterface
143
     */
144 6
    protected function resolveMiddleware($middleware): MiddlewareInterface
145
    {
146 6
        $middleware = $this->resolveMiddlewareWithContainer($middleware);
147 6
        $middleware = $this->resolveMiddlewareWithoutContainer($middleware);
148
149 6
        if ($middleware instanceof MiddlewareInterface) {
150 5
            return $middleware;
151
        }
152
153 1
        throw new InvalidArgumentException(sprintf('Could not resolve middleware class: %s', (string) $middleware));
154
    }
155
156
    /**
157
     * Resolve middleware without container
158
     *
159
     * @param MiddlewareInterface|string $middleware
160
     *
161
     * @return MiddlewareInterface|string
162
     */
163 6
    protected function resolveMiddlewareWithoutContainer($middleware)
164
    {
165 6
        if ($this->container === null && is_string($middleware) && class_exists($middleware)) {
166 1
            $middleware = new $middleware;
167
        }
168 6
        return $middleware;
169
    }
170
171
    /**
172
     * Resolve middleware with container
173
     *
174
     * @param MiddlewareInterface|string $middleware
175
     *
176
     * @return MiddlewareInterface|string
177
     */
178 6
    protected function resolveMiddlewareWithContainer($middleware)
179
    {
180 6
        if ($this->container !== null && is_string($middleware) && $this->container->has($middleware)) {
181 2
            $middleware = $this->container->get($middleware);
182
        }
183 6
        return $middleware;
184
    }
185
}
186