Passed
Pull Request — master (#1104)
by Aleksei
26:20
created

ReflectionHandler::handle()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 39
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 6.0026

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 20
dl 0
loc 39
ccs 23
cts 24
cp 0.9583
rs 8.9777
c 1
b 0
f 0
cc 6
nc 10
nop 1
crap 6.0026
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 8
    public function __construct(
22
        /** @internal */
23
        protected ContainerInterface $container,
24
        protected bool $resolveFromPath = true,
25
    ) {
26 8
    }
27
28
    /**
29
     * @psalm-assert class-string $controller
30
     * @psalm-assert non-empty-string $action
31
     * @throws \Throwable
32
     */
33 8
    public function handle(CallContext $context): mixed
34
    {
35
        // Resolve controller method
36 8
        $method = $context->getTarget()->getReflection();
37 8
        $path = $context->getTarget()->getPath();
38 8
        if ($method === null) {
39 4
            $this->resolveFromPath or throw new TargetCallException(
40 4
                "Reflection not provided for target `{$context->getTarget()}`.",
41 4
                TargetCallException::NOT_FOUND,
42 4
            );
43
44 3
            if (\count($path) !== 2) {
45 1
                throw new TargetCallException(
46 1
                    "Invalid target path to resolve reflection for `{$context->getTarget()}`."
47 1
                    . ' Expected two parts: class and method.',
48 1
                    TargetCallException::NOT_FOUND,
49 1
                );
50
            }
51
52 2
            $method = ActionResolver::pathToReflection(\reset($path), \next($path));
53
        }
54
55 5
        if ($method instanceof \ReflectionFunction) {
56 2
            return $method->invokeArgs(
57 2
                $this->resolveArguments($method, $context)
58 2
            );
59
        }
60
61 3
        if (!$method instanceof \ReflectionMethod) {
62
            throw new TargetCallException("Action not found for target `{$context->getTarget()}`.");
63
        }
64
65 3
        $controller = $context->getTarget()->getObject() ?? $this->container->get($path[0]);
66
67
        // Validate method and controller
68 3
        ActionResolver::validateControllerMethod($method, $controller);
69
70
        // Run action
71 3
        return $method->invokeArgs($controller, $this->resolveArguments($method, $context));
72
    }
73
74
    /**
75
     * @throws ContainerExceptionInterface
76
     */
77 5
    protected function resolveArguments(\ReflectionFunctionAbstract $method, CallContext $context): array
78
    {
79 5
        $resolver = $this->container->get(ResolverInterface::class);
80 5
        \assert($resolver instanceof ResolverInterface);
81
82 5
        return $resolver->resolveArguments($method, $context->getArguments());
83
    }
84
}
85