Completed
Push — master ( 7cee72...1d5e18 )
by Dan
01:46
created

AutoWireServiceLocator::locate()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 10
nc 4
nop 2
dl 0
loc 18
ccs 9
cts 9
cp 1
crap 4
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
namespace danmurf\DependencyInjection;
4
5
use danmurf\DependencyInjection\Exception\ContainerException;
6
use danmurf\DependencyInjection\Exception\NotFoundException;
7
use Psr\Container\ContainerInterface;
8
use ReflectionClass;
9
use ReflectionException;
10
use ReflectionParameter;
11
12
class AutoWireServiceLocator extends ConfigurableServiceLocator
13
{
14
    /**
15
     * If the service doesn't exist in config, attemtpt to autowire it.
16
     *
17
     * @param string             $id        The service ID or FQCN
18
     * @param ContainerInterface $container The container to get service dependencies from
19
     *
20
     * @throws NotFoundException
21
     * @throws ContainerException
22
     */
23 4
    public function locate($id, ContainerInterface $container)
24
    {
25
        try {
26 4
            return parent::locate($id, $container);
27 4
        } catch (NotFoundException $exception) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
28
        }
29
30
        try {
31 4
            $class = new ReflectionClass($id);
32 1
        } catch (ReflectionException $exception) {
33 1
            throw new NotFoundException(sprintf('Unable to autowire class `%s`.', $id));
34
        }
35
36 3
        if (null !== $class->getConstructor()) {
37 2
            return $this->instantiateClassWithConstructor($class, $container, $id);
38
        }
39
40 1
        return $class->newInstance();
41
    }
42
43
    /**
44
     * Get a dependency from a method parameter.
45
     *
46
     * @param ReflectionParameter $parameter
47
     * @param ContainerInterface  $container
48
     * @param string              $id
49
     *
50
     * @return mixed
51
     *
52
     * @throws ContainerException
53
     */
54 2
    public function getParameterInstance(
55
        ReflectionParameter $parameter,
56
        ContainerInterface $container,
57
        string $id
58
    ) {
59 2
        if (null === $dependencyClass = $parameter->getClass()) {
60 1
            throw new ContainerException(sprintf(
61 1
                'Unable to autowire service `%s` as it has scalar arguments.',
62 1
                $id
63
            ));
64
        }
65
66 2
        return $container->get($dependencyClass->getName());
67
    }
68
69
    /**
70
     * Get a new instance of a class with constructor arguments.
71
     *
72
     * @param ReflectionClass    $class
73
     * @param ContainerInterface $container
74
     * @param string             $id
75
     *
76
     * @return mixed
77
     *
78
     * @throws ContainerException
79
     */
80 2
    private function instantiateClassWithConstructor(
81
        ReflectionClass $class,
82
        ContainerInterface $container,
83
        string $id
84
    ) {
85 2
        $args = [];
86 2
        foreach ($class->getConstructor()->getParameters() as $parameter) {
87 2
            $args[] = $this->getParameterInstance($parameter, $container, $id);
88
        }
89
90 1
        return $class->newInstanceArgs($args);
91
    }
92
}
93