Passed
Pull Request — master (#1095)
by Aleksei
11:58 queued 42s
created

ReflectionHandler::handle()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 39
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 6

Importance

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