Passed
Branch v0.2 (3b8de8)
by Freddie
05:06
created

DispatchController::resolveArgs()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 25
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 5
nop 3
dl 0
loc 25
rs 8.5806
c 0
b 0
f 0
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
class DispatchController
21
{
22
    /** @var RouteParamsRegistry */
23
    private $routeParamsRegistry;
24
25
    /** @var ContainerInterface */
26
    private $container;
27
28
    public function __construct(RouteParamsRegistry $routeParamsRegistry, ContainerInterface $container)
29
    {
30
        $this->routeParamsRegistry = $routeParamsRegistry;
31
        $this->container = $container;
32
    }
33
34
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
35
    {
36
        $controllerRouteParam = $this->routeParamsRegistry->getParameter(RouteParamsRegistry::CONTROLLER_KEY);
37
38
        $controller = $this->getController($this->getControllerClass($controllerRouteParam));
39
40
        $this->injectControllerDependencies($controller);
41
42
        $controller->setResponse($response);
43
44
        $args = $this->resolveArgs(
45
            $request,
46
            $this->getControllerClass($controllerRouteParam),
47
            $this->getControllerAction($controllerRouteParam)
48
        );
49
50
        $response = $this->invokeController(
51
            $controller,
52
            $this->getControllerAction($controllerRouteParam),
53
            $args
54
        );
55
56
        return $next($request, $response);
57
    }
58
59
    private function getControllerClass(string $controllerRouteParam): string
60
    {
61
        return explode('::', $controllerRouteParam)[0];
62
    }
63
64
    private function getControllerAction(string $controllerRouteParam): string
65
    {
66
        return explode('::', $controllerRouteParam)[1];
67
    }
68
69
    private function getController(string $controllerClass): Controller
70
    {
71
        return $this->container->get($controllerClass);
72
    }
73
74
    private function injectControllerDependencies($controller): void
75
    {
76
        if (!$this->container->has(ContainerKeys::CONTROLLER_DEPENDENCIES)) {
77
            return;
78
        }
79
80
        $map = $this->container->get(ContainerKeys::CONTROLLER_DEPENDENCIES);
81
82
        foreach ($map as $controllerClass => $dependencies) {
83
            if (!$controller instanceof $controllerClass) {
84
                continue;
85
            }
86
87
            foreach ($dependencies as $setterName => $object) {
88
                $controller->{'set' . ucfirst($setterName)}($object);
89
            }
90
        }
91
    }
92
93
    private function resolveArgs(
94
        ServerRequestInterface $request,
95
        string $controllerClass,
96
        string $controllerMethod): array
97
    {
98
        $method = new \ReflectionMethod($controllerClass, $controllerMethod);
99
100
        $args = [];
101
102
        $methodParameters = $method->getParameters();
103
104
        $routeParameters = $this->routeParamsRegistry->getRouteParams();
105
106
        foreach ($methodParameters as $parameter) {
107
108
            if ($this->parameterIsOfType($parameter,ServerRequestInterface::class)) {
109
                $args[] = $request;
110
            }
111
112
            if (array_key_exists($parameter->getName(), $routeParameters)) {
113
                $args[] = $routeParameters[$parameter->getName()];
114
            }
115
        }
116
117
        return $args;
118
    }
119
120
    private function parameterIsOfType(\ReflectionParameter $parameter, string $class): bool
121
    {
122
        return ($parameter->getClass() !== null) && $parameter->getClass()->getName() === $class;
123
    }
124
125
    private function invokeController(Controller $controller, string $action, array $args): ResponseInterface
126
    {
127
        $response = call_user_func_array(
128
            [
129
                $controller,
130
                $action,
131
            ],
132
            $args
133
        );
134
135
        if (!$response instanceof ResponseInterface) {
136
            throw new \LogicException(
137
                get_class($controller) . ' must return an instance of ' . ResponseInterface::class
138
            );
139
        }
140
141
        return $response;
142
    }
143
}
144