Completed
Push — master ( 1f8f60...98572a )
by Koldo
02:48
created

InstanceResolver::getExistingParameter()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4

Importance

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