Passed
Push — master ( db330e...dfa377 )
by Koldo
02:43
created

InstanceResolver::setInstanceOf()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 2
b 0
f 0
nc 3
nop 1
dl 0
loc 9
ccs 6
cts 6
cp 1
crap 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Antidot\Container;
6
7
8
use Psr\Container\ContainerInterface;
9
use ReflectionClass;
10
use ReflectionMethod;
11
use ReflectionParameter;
12
13
class InstanceResolver
14
{
15
    private $config;
16
    private $instances;
17
    private $parameters;
18
    private $container;
19
20 9
    public function __construct(ContainerConfig $config, InstanceCollection $instances, ContainerInterface $container)
21
    {
22 9
        $this->config = $config;
23 9
        $this->instances = $instances;
24 9
        $this->parameters = new ParamCollection($config->get('parameters'));
25 9
        $this->container = $container;
26 9
    }
27
28 9
    public function setInstanceOf(string $id): void
29
    {
30 9
        if ($this->config->has($id)) {
31 8
            $this->setConfiguredInstance($id);
32 8
            return;
33
        }
34
35 4
        if (class_exists($id)) {
36 4
            $this->instances->set($id, $this->getAnInstanceOf($id, $id));
37
        }
38 3
    }
39
40 8
    private function getAnInstanceOf(string $id, string $className)
41
    {
42 8
        $this->parameters->set($id, $this->parameters->has($id) ? $this->parameters->get($id) : []);
43 8
        $instance = new ReflectionClass($className);
44 8
        if (false === $instance->hasMethod('__construct')) {
45 6
            return $instance->newInstance();
46
        }
47
48 5
        $parameters = (new ReflectionMethod($className, '__construct'))->getParameters();
49
50
        $this->parameters->set($id, array_map(function (ReflectionParameter $parameter) use ($id) {
51 5
            return $this->makeParameter($id, $parameter);
52 5
        }, $parameters));
53
54 4
        return $instance->newInstanceArgs($this->parameters->get($id));
55
    }
56
57 5
    private function makeParameter(string $id, ReflectionParameter $parameter)
58
    {
59 5
        $type = null === $parameter->getType() ? '' : $parameter->getType()->getName();
60 5
        if (array_key_exists($parameter->getName(), $this->parameters->get($id))) {
61 2
            return $this->getExistingParameter($id, $parameter, $type);
62
        }
63
64 4
        if ($this->container->has($type)) {
65 1
            return $this->container->get($type);
66
        }
67
68 4
        if ($parameter->isDefaultValueAvailable()) {
69 3
            return $parameter->getDefaultValue();
70
        }
71
72 4
        if ('' === $type) {
73 1
            throw AutowiringException::withNoType($id, $parameter->getName());
74
        }
75
76 3
        return $this->getAnInstanceOf($type, $type);
77
    }
78
79 2
    private function getExistingParameter(string $id, ReflectionParameter $parameter, $type)
80
    {
81 2
        if (is_array($this->parameters->get($id)[$parameter->getName()])
82 2
            || $this->parameters->get($id)[$parameter->getName()] instanceof $type) {
83 1
            return $this->parameters->get($id)[$parameter->getName()];
84
        }
85
86 2
        if ($this->container->has($this->parameters->get($id)[$parameter->getName()])) {
87 1
            return $this->container->get($this->parameters->get($id)[$parameter->getName()]);
88
        }
89
90 2
        return $this->parameters->get($id)[$parameter->getName()];
91
    }
92
93 8
    private function setConfiguredInstance(string $id): void
94
    {
95 8
        if (is_callable($this->config->get($id))) {
96 4
            $callable = $this->config->get($id);
97 4
            $this->instances->set($id, $callable($this->container));
98 4
            return;
99
        }
100
101 5
        if (is_string($this->config->get($id)) && class_exists($this->config->get($id))) {
102 5
            $this->instances->set($id, $this->getAnInstanceOf($id, $this->config->get($id)));
103 5
            return;
104
        }
105
106 1
        if (is_string($this->config->get($id)) && $this->container->has($this->config->get($id))) {
107 1
            $this->instances->set($id, $this->container->get($this->config->get($id)));
108 1
            return;
109
        }
110
    }
111
}
112