Test Failed
Pull Request — master (#1095)
by Aleksei
10:19
created

ReflectionHandler   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 68
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 8
eloc 24
c 1
b 0
f 0
dl 0
loc 68
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
B handle() 0 39 6
A __construct() 0 5 1
A resolveArguments() 0 6 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spiral\Interceptors\Handler;
6
7
use Psr\Container\ContainerExceptionInterface;
8
use Psr\Container\ContainerInterface;
9
use Spiral\Core\ResolverInterface;
10
use Spiral\Interceptors\Context\CallContext;
11
use Spiral\Interceptors\Exception\TargetCallException;
12
use Spiral\Interceptors\HandlerInterface;
13
use Spiral\Interceptors\Internal\ActionResolver;
14
15
class ReflectionHandler implements HandlerInterface
16
{
17
    /**
18
     * @param bool $resolveFromPath Try to resolve controller and action reflection from the target path if
19
     *        reflection is not provided.
20
     */
21
    public function __construct(
22
        /** @internal */
23
        protected ContainerInterface $container,
24
        protected bool $resolveFromPath = true,
25
    ) {
26
    }
27
28
    /**
29
     * @psalm-assert class-string $controller
30
     * @psalm-assert non-empty-string $action
31
     * @throws \Throwable
32
     */
33
    public function handle(CallContext $context): mixed
34
    {
35
        // Resolve controller method
36
        $method = $context->getTarget()->getReflection();
37
        if ($method === null) {
38
            $this->resolveFromPath or throw new TargetCallException(
39
                "Reflection not provided for target `{$context->getTarget()}`.",
40
                TargetCallException::NOT_FOUND,
41
            );
42
43
            $path = $context->getTarget()->getPath();
44
            if (\count($path) !== 2) {
45
                throw new TargetCallException(
46
                    "Invalid target path to resolve reflection for `{$context->getTarget()}`."
47
                    . ' Expected two parts: class and method.',
48
                    TargetCallException::NOT_FOUND,
49
                );
50
            }
51
52
            $method = ActionResolver::pathToReflection(\reset($path), \end($path));
53
        }
54
55
        if ($method instanceof \ReflectionFunction) {
56
            return $method->invokeArgs(
57
                $this->resolveArguments($method, $context)
58
            );
59
        }
60
61
        if (!$method instanceof \ReflectionMethod) {
62
            throw new TargetCallException("Action not found for target `{$context->getTarget()}`.");
63
        }
64
65
        $controller = $this->container->get($method->getDeclaringClass()->getName());
66
67
        // Validate method and controller
68
        ActionResolver::validateControllerMethod($method, $controller);
69
70
        // Run action
71
        return $method->invokeArgs($controller, $this->resolveArguments($method, $context));
72
    }
73
74
    /**
75
     * @throws ContainerExceptionInterface
76
     */
77
    protected function resolveArguments(\ReflectionFunctionAbstract $method, CallContext $context): array
78
    {
79
        $resolver = $this->container->get(ResolverInterface::class);
80
        \assert($resolver instanceof ResolverInterface);
81
82
        return $resolver->resolveArguments($method, $context->getArguments());
83
    }
84
}
85