AutoWireServiceLocator::locate()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 4
eloc 10
c 5
b 0
f 0
nc 4
nop 2
dl 0
loc 19
ccs 9
cts 9
cp 1
crap 4
rs 9.9332
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
     * Load services by infering their dependencies if they aren't specified in config.
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) {
28
            // Service isn't in config, so attempt to autowire...
29
        }
30
31
        try {
32 4
            $class = new ReflectionClass($id);
33 1
        } catch (ReflectionException $exception) {
34 1
            throw new NotFoundException(sprintf('Unable to autowire class `%s`.', $id));
35
        }
36
37 3
        if (null !== $class->getConstructor()) {
38 2
            return $this->instantiateClassWithConstructor($class, $container, $id);
39
        }
40
41 1
        return $class->newInstance();
42
    }
43
44
    /**
45
     * Get a dependency from a method parameter.
46
     *
47
     * @param ReflectionParameter $parameter
48
     * @param ContainerInterface  $container
49
     * @param string              $id
50
     *
51
     * @return mixed
52
     *
53
     * @throws ContainerException
54
     */
55 2
    private function getParameterInstance(
56
        ReflectionParameter $parameter,
57
        ContainerInterface $container,
58
        string $id
59
    ) {
60 2
        if (null === $dependencyClass = $parameter->getClass()) {
61 1
            throw new ContainerException(sprintf(
62 1
                'Unable to autowire service `%s` as it has scalar arguments.',
63
                $id
64
            ));
65
        }
66
67 2
        return $container->get($dependencyClass->getName());
68
    }
69
70
    /**
71
     * Get a new instance of a class with constructor arguments.
72
     *
73
     * @param ReflectionClass    $class
74
     * @param ContainerInterface $container
75
     * @param string             $id
76
     *
77
     * @return mixed
78
     *
79
     * @throws ContainerException
80
     */
81 2
    private function instantiateClassWithConstructor(
82
        ReflectionClass $class,
83
        ContainerInterface $container,
84
        string $id
85
    ) {
86 2
        $args = [];
87 2
        foreach ($class->getConstructor()->getParameters() as $parameter) {
88 2
            $args[] = $this->getParameterInstance($parameter, $container, $id);
89
        }
90
91 1
        return $class->newInstanceArgs($args);
92
    }
93
}
94