Completed
Push — master ( b5a902...024bcd )
by Changwan
04:42
created

PsrLoader::createInstance()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 18
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5.1158

Importance

Changes 0
Metric Value
cc 5
eloc 14
nc 7
nop 2
dl 0
loc 18
ccs 10
cts 12
cp 0.8333
crap 5.1158
rs 8.8571
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 6
    public function __construct(ContainerInterface $container)
23
    {
24 6
        $this->container = $container;
25 6
    }
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 4
    public function execute(string $className, string $methodName, ServerRequestInterface $request)
41
    {
42
        try {
43 4
            $object = $this->createInstance($className, $request);
44
            try {
45 4
                $reflMethod = (new ReflectionClass($className))->getMethod($methodName);
46 1
            } catch (ReflectionException $e) {
47 1
                $reflMethod = null;
48
            }
49 4
            if ($reflMethod) {
50 3
                $arguments = $this->getArguments($reflMethod, $request);
51 3
                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 6
    public function createInstance(string $className, ServerRequestInterface $request)
68
    {
69 6
        if (class_exists($className)) {
70 5
            $classRefl = new ReflectionClass($className);
71 5
            $constructor = $classRefl->getConstructor();
72
            try {
73 5
                if ($constructor) {
74 2
                    $arguments = $this->getArguments($constructor, $request);
75 2
                    return new $className(...$arguments);
76
                } else {
77 4
                    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 4
    protected function getArguments(\ReflectionFunctionAbstract $refl, ServerRequestInterface $request)
92
    {
93 4
        $arguments = [];
94
        // it from container Resolver..
95 4
        foreach ($refl->getParameters() as $param) {
96 3
            $paramClass = $param->getClass();
97 3
            if ($paramClass) { // #2.
98 3
                if ($paramClass->isInstance($request)) {
99 2
                    $arguments[] = $request;
100 2
                    continue;
101
                }
102 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...
103 2
                if ($attribute = $request->getAttribute($paramClassName)) {
104 1
                    $arguments[] = $attribute;
105 1
                    continue;
106
                }
107 2
                if ($this->container->has($paramClassName)) {
108
                    try {
109 2
                        $arguments[] = $this->container->get($paramClassName);
110 1
                        continue;
111 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...
112
                    }
113
                }
114
            }
115 1
            if ($param->isDefaultValueAvailable()) {
116
                $arguments[] = $param->getDefaultValue();
117
                continue;
118
            }
119 1
            if ($attribute = $request->getAttribute($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...
120
                $arguments[] = $attribute;
121
                continue;
122
            }
123 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...
124
        }
125 4
        return $arguments;
126
    }
127
}
128