Completed
Push — master ( a197f9...5db1cf )
by Changwan
02:31
created

PsrLoader::getArguments()   D

Complexity

Conditions 9
Paths 13

Size

Total Lines 38
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 9.0368

Importance

Changes 0
Metric Value
cc 9
eloc 27
nc 13
nop 2
dl 0
loc 38
ccs 24
cts 26
cp 0.9231
crap 9.0368
rs 4.909
c 0
b 0
f 0
1
<?php
2
namespace Wandu\Router\Loader;
3
4
use Psr\Container\ContainerInterface;
5
use Psr\Container\NotFoundExceptionInterface;
6
use Psr\Http\Message\ServerRequestInterface;
7
use ReflectionClass;
8
use RuntimeException;
9
use ReflectionException;
10
use Wandu\Router\Contracts\LoaderInterface;
11
use Wandu\Router\Contracts\MiddlewareInterface;
12
use Wandu\Router\Exception\HandlerNotFoundException;
13
14
class PsrLoader implements LoaderInterface
15
{
16
    /** @var \Psr\Container\ContainerInterface */
17
    protected $container;
18
19
    /**
20
     * @param \Psr\Container\ContainerInterface $container
21
     */
22 7
    public function __construct(ContainerInterface $container)
23
    {
24 7
        $this->container = $container;
25 7
    }
26
27
    /**
28
     * {@inheritdoc}
29
     */
30 3
    public function middleware(string $className, ServerRequestInterface $request): MiddlewareInterface
31
    {
32
        /** @var \Wandu\Router\Contracts\MiddlewareInterface $instance */
33 3
        $instance = $this->createInstance($className, $request);
34 2
        return $instance;
35
    }
36
37
    /**
38
     * {@inheritdoc}
39
     */
40 5
    public function execute(string $className, string $methodName, ServerRequestInterface $request)
41
    {
42
        try {
43 5
            $object = $this->createInstance($className, $request);
44
            try {
45 5
                $reflMethod = (new ReflectionClass($className))->getMethod($methodName);
46 1
            } catch (ReflectionException $e) {
47 1
                $reflMethod = null;
48
            }
49 5
            if ($reflMethod) {
50 4
                $arguments = $this->getArguments($reflMethod, $request);
51 4
                return call_user_func_array([$object, $methodName], $arguments);
52
            }
53 1
            if (method_exists($object, '__call')) {
54 1
                return $object->__call($methodName, [$request]);
55
            }
56 1
        } catch (HandlerNotFoundException $e) {
57
            throw new HandlerNotFoundException($className, $methodName);
58
        }
59
        throw new HandlerNotFoundException($className, $methodName);
60
    }
61
62
    /**
63
     * @param string $className
64
     * @param \Psr\Http\Message\ServerRequestInterface $request
65
     * @return object
66
     */
67 7
    public function createInstance(string $className, ServerRequestInterface $request)
68
    {
69 7
        if (class_exists($className)) {
70 6
            $classRefl = new ReflectionClass($className);
71 6
            $constructor = $classRefl->getConstructor();
72
            try {
73 6
                if ($constructor) {
74 2
                    $arguments = $this->getArguments($constructor, $request);
75 2
                    return new $className(...$arguments);
76
                } else {
77 5
                    return new $className();
78
                }
79
            } catch (RuntimeException $e) {}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
80 1
        } elseif ($this->container->has($className)) { // for alias
81
            return $this->container->get($className);
82
        }
83 1
        throw new HandlerNotFoundException($className);
84
    }
85
86
    /**
87
     * @param \ReflectionFunctionAbstract $refl
88
     * @param \Psr\Http\Message\ServerRequestInterface $request
89
     * @return array
90
     */
91 5
    protected function getArguments(\ReflectionFunctionAbstract $refl, ServerRequestInterface $request)
92
    {
93 5
        $requestAttrs = $request->getAttributes();
94 5
        $arguments = [];
95
        // it from container Resolver..
96 5
        foreach ($refl->getParameters() as $param) {
97 4
            $paramClass = $param->getClass();
98 4
            if ($paramClass) { // #2.
99 3
                if ($paramClass->isInstance($request)) {
100 2
                    $arguments[] = $request;
101 2
                    continue;
102
                }
103 2
                $paramClassName = $paramClass->getName();
0 ignored issues
show
Bug introduced by
Consider using $paramClass->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
104 2
                if (array_key_exists($paramClassName, $requestAttrs)) {
105 1
                    $arguments[] = $requestAttrs[$paramClassName];
106 1
                    continue;
107
                }
108 2
                if ($this->container->has($paramClassName)) {
109
                    try {
110 2
                        $arguments[] = $this->container->get($paramClassName);
111 1
                        continue;
112 1
                    } catch (NotFoundExceptionInterface $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
113
                    }
114
                }
115
            }
116 2
            if ($param->isDefaultValueAvailable()) {
117
                $arguments[] = $param->getDefaultValue();
118
                continue;
119
            }
120 2
            $paramName = $param->getName();
0 ignored issues
show
Bug introduced by
Consider using $param->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
121 2
            if (array_key_exists($paramName, $requestAttrs)) {
122 1
                $arguments[] = $requestAttrs[$paramName];
123 1
                continue;
124
            }
125 1
            throw new RuntimeException("not found parameter named \"{$param->getName()}\".");
0 ignored issues
show
Bug introduced by
Consider using $param->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
126
        }
127 5
        return $arguments;
128
    }
129
}
130