Completed
Push — master ( 29f7ac...56fa27 )
by Anton
01:47
created

Std::resolveClass()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 10
cc 3
nc 2
nop 1
crap 3
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 15
    public function processHandler(ServerRequestInterface $request, $handler, array $variables): ResponseInterface
50
    {
51 15
        $controller = $this->getCallable($handler);
52 12
        return $controller($request, $variables);
53
    }
54
55
    /**
56
     * Get the controller callable
57
     *
58
     * @param $callable callable|string|array|object
59
     *
60
     * @return callable
61
     */
62 15
    public function getCallable($callable)
63
    {
64 15
        if (is_string($callable)) {
65 3
            $callable = $this->getCallableFromString($callable);
66
        }
67
68 15
        if (is_array($callable)) {
69 6
            $callable = $this->getCallableFromArray($callable);
70
        }
71
72 15
        if (!is_callable($callable)) {
73 3
            throw new InvalidArgumentException('Could not resolve a callable for this route');
74
        }
75
76 12
        return $callable;
77
    }
78
79
    /**
80
     * Get callable from string
81
     *
82
     * @param string $callable
83
     *
84
     * @return callable|object|array|string
85
     */
86 3
    public function getCallableFromString(string $callable)
87
    {
88 3
        if (strpos($callable, '::') !== false) {
89 1
            return explode('::', $callable);
90
        }
91 2
        if (method_exists($callable, '__invoke')) {
92 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

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