Passed
Push — master ( 18c703...d77f42 )
by Freddie
10:17
created

DispatchController   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Test Coverage

Coverage 90.74%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 48
c 2
b 0
f 0
dl 0
loc 122
ccs 49
cts 54
cp 0.9074
rs 10
wmc 18

9 Methods

Rating   Name   Duplication   Size   Complexity  
A getControllerAction() 0 3 1
A getControllerClass() 0 3 1
A parameterIsOfType() 0 3 2
A invokeController() 0 17 2
A resolveArgs() 0 25 4
A __invoke() 0 23 1
A injectControllerDependencies() 0 15 5
A getController() 0 3 1
A __construct() 0 4 1
1
<?php declare(strict_types = 1);
2
3
/**
4
 * This file is part of the Simplex package.
5
 *
6
 * (c) Freddie Frantzen <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
namespace Simplex\HttpMiddleware;
12
13
use Psr\Container\ContainerInterface;
14
use Psr\Http\Message\ResponseInterface;
15
use Psr\Http\Message\ServerRequestInterface;
16
use Simplex\ContainerKeys;
17
use Simplex\Controller;
18
use Simplex\Routing\RouteParamsRegistry;
19
20
final class DispatchController
21
{
22
    /** @var RouteParamsRegistry */
23
    private $routeParamsRegistry;
24
25
    /** @var ContainerInterface */
26
    private $container;
27
28 2
    public function __construct(RouteParamsRegistry $routeParamsRegistry, ContainerInterface $container)
29
    {
30 2
        $this->routeParamsRegistry = $routeParamsRegistry;
31 2
        $this->container = $container;
32 2
    }
33
34 2
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
35
    {
36 2
        $controllerRouteParam = $this->routeParamsRegistry->getParameter(RouteParamsRegistry::CONTROLLER_KEY);
37
38 2
        $controller = $this->getController($this->getControllerClass($controllerRouteParam));
39
40 2
        $this->injectControllerDependencies($controller);
41
42 2
        $controller->setResponse($response);
43
44 2
        $args = $this->resolveArgs(
45 2
            $request,
46 2
            $this->getControllerClass($controllerRouteParam),
47 2
            $this->getControllerAction($controllerRouteParam)
48
        );
49
50 2
        $response = $this->invokeController(
51 2
            $controller,
52 2
            $this->getControllerAction($controllerRouteParam),
53
            $args
54
        );
55
56 2
        return $next($request, $response);
57
    }
58
59 2
    private function getControllerClass(string $controllerRouteParam): string
60
    {
61 2
        return explode('::', $controllerRouteParam)[0];
62
    }
63
64 2
    private function getControllerAction(string $controllerRouteParam): string
65
    {
66 2
        return explode('::', $controllerRouteParam)[1];
67
    }
68
69 2
    private function getController(string $controllerClass): Controller
70
    {
71 2
        return $this->container->get($controllerClass);
72
    }
73
74 2
    private function injectControllerDependencies($controller): void
75
    {
76 2
        if (!$this->container->has(ContainerKeys::CONTROLLER_DEPENDENCIES)) {
77
            return;
78
        }
79
80 2
        $map = $this->container->get(ContainerKeys::CONTROLLER_DEPENDENCIES);
81
82 2
        foreach ($map as $controllerClass => $dependencies) {
83 2
            if (!$controller instanceof $controllerClass) {
84
                continue;
85
            }
86
87 2
            foreach ($dependencies as $setterName => $object) {
88 2
                $controller->{'set' . ucfirst($setterName)}($object);
89
            }
90
        }
91 2
    }
92
93 2
    private function resolveArgs(
94
        ServerRequestInterface $request,
95
        string $controllerClass,
96
        string $controllerMethod
97
    ): array {
98 2
        $method = new \ReflectionMethod($controllerClass, $controllerMethod);
99
100 2
        $args = [];
101
102 2
        $methodParameters = $method->getParameters();
103
104 2
        $routeParameters = $this->routeParamsRegistry->getRouteParams();
105
106 2
        foreach ($methodParameters as $parameter) {
107
108 2
            if ($this->parameterIsOfType($parameter, ServerRequestInterface::class)) {
109
                $args[] = $request;
110
            }
111
112 2
            if (array_key_exists($parameter->getName(), $routeParameters)) {
113 2
                $args[] = $routeParameters[$parameter->getName()];
114
            }
115
        }
116
117 2
        return $args;
118
    }
119
120 2
    private function parameterIsOfType(\ReflectionParameter $parameter, string $class): bool
121
    {
122 2
        return ($parameter->getClass() !== null) && $parameter->getClass()->getName() === $class;
123
    }
124
125 2
    private function invokeController(Controller $controller, string $action, array $args): ResponseInterface
126
    {
127 2
        $response = call_user_func_array(
128
            [
129 2
                $controller,
130 2
                $action,
131
            ],
132
            $args
133
        );
134
135 2
        if (!$response instanceof ResponseInterface) {
136
            throw new \LogicException(
137
                get_class($controller) . ' must return an instance of ' . ResponseInterface::class
138
            );
139
        }
140
141 2
        return $response;
142
    }
143
}
144