Completed
Push — master ( 495169...b31514 )
by Changwan
10:11
created

PsrLoader::createInstance()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4.25

Importance

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