InstanceResolver   A
last analyzed

Complexity

Total Complexity 24

Size/Duplication

Total Lines 109
Duplicated Lines 0 %

Test Coverage

Coverage 98.18%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 24
eloc 51
c 2
b 0
f 0
dl 0
loc 109
ccs 54
cts 55
cp 0.9818
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A makeParameter() 0 22 6
A setConfiguredInstance() 0 16 6
A __construct() 0 6 1
A setInstanceOf() 0 9 3
A getExistingParameter() 0 12 4
A getAnInstanceOf() 0 18 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Antidot\Container;
6
7
use InvalidArgumentException;
8
use Psr\Container\ContainerInterface;
9
use ReflectionClass;
10
use ReflectionMethod;
11
use ReflectionNamedType;
12
use ReflectionParameter;
13
14
use function class_exists;
15
use function sprintf;
16
17
class InstanceResolver
18
{
19
    private ContainerConfig $config;
20
    private InstanceCollection $instances;
21
    private ParamCollection $parameters;
22
    private ContainerInterface $container;
23
24 21
    public function __construct(ContainerConfig $config, InstanceCollection $instances, ContainerInterface $container)
25
    {
26 21
        $this->config = $config;
27 21
        $this->instances = $instances;
28 21
        $this->parameters = new ParamCollection($config->get('parameters'));
29 21
        $this->container = $container;
30 21
    }
31
32 16
    public function setInstanceOf(string $id): void
33
    {
34 16
        if ($this->config->has($id)) {
35 15
            $this->setConfiguredInstance($id);
36 15
            return;
37
        }
38
39 6
        if (class_exists($id)) {
40 6
            $this->instances->set($id, $this->getAnInstanceOf($id, $id));
41
        }
42 5
    }
43
44 13
    private function getAnInstanceOf(string $id, string $className): object
45
    {
46 13
        $this->parameters->set($id, $this->parameters->has($id) ? $this->parameters->get($id) : []);
47 13
        if (false === class_exists($className)) {
48
            throw new InvalidArgumentException(sprintf('Class "%s" not found for service id "%s".', $className, $id));
49
        }
50 13
        $instance = new ReflectionClass($className);
51 13
        if (false === $instance->hasMethod('__construct')) {
52 10
            return $instance->newInstance();
53
        }
54
55 8
        $parameters = (new ReflectionMethod($className, '__construct'))->getParameters();
56
57 8
        $this->parameters->set($id, array_map(function (ReflectionParameter $parameter) use ($id) {
58 8
            return $this->makeParameter($id, $parameter);
59 8
        }, $parameters));
60
61 7
        return $instance->newInstanceArgs($this->parameters->get($id));
62
    }
63
64
    /**
65
     * @return mixed|object
66
     * @throws \ReflectionException
67
     */
68 8
    private function makeParameter(string $id, ReflectionParameter $parameter)
69
    {
70
        /** @var null|ReflectionNamedType $paramType */
71 8
        $paramType = $parameter->getType();
72 8
        $type = null === $paramType ? '' : $paramType->getName();
73 8
        if (array_key_exists($parameter->getName(), $this->parameters->get($id))) {
74 3
            return $this->getExistingParameter($id, $parameter, $type);
75
        }
76
77 6
        if ($this->container->has($type)) {
78 1
            return $this->container->get($type);
79
        }
80
81 6
        if ($parameter->isDefaultValueAvailable()) {
82 5
            return $parameter->getDefaultValue();
83
        }
84
85 6
        if ('' === $type) {
86 1
            throw AutowiringException::withNoType($id, $parameter->getName());
87
        }
88
89 5
        return $this->getAnInstanceOf($type, $type);
90
    }
91
92
    /**
93
     * @param string $type
94
     * @return mixed
95
     */
96 3
    private function getExistingParameter(string $id, ReflectionParameter $parameter, string $type)
97
    {
98 3
        if (is_array($this->parameters->get($id)[$parameter->getName()])
99 3
            || $this->parameters->get($id)[$parameter->getName()] instanceof $type) {
100 1
            return $this->parameters->get($id)[$parameter->getName()];
101
        }
102
103 3
        if ($this->container->has($this->parameters->get($id)[$parameter->getName()])) {
104 1
            return $this->container->get($this->parameters->get($id)[$parameter->getName()]);
105
        }
106
107 3
        return $this->parameters->get($id)[$parameter->getName()];
108
    }
109
110 15
    private function setConfiguredInstance(string $id): void
111
    {
112 15
        if (is_callable($this->config->get($id))) {
113 8
            $callable = $this->config->get($id);
114 8
            $this->instances->set($id, $callable($this->container));
115 8
            return;
116
        }
117
118 8
        if (is_string($this->config->get($id)) && class_exists($this->config->get($id))) {
119 8
            $this->instances->set($id, $this->getAnInstanceOf($id, $this->config->get($id)));
120 8
            return;
121
        }
122
123 1
        if (is_string($this->config->get($id)) && $this->container->has($this->config->get($id))) {
124 1
            $this->instances->set($id, $this->container->get($this->config->get($id)));
125 1
            return;
126
        }
127
    }
128
}
129