Passed
Push — master ( 64b3e0...a89ccd )
by Alexander
04:43 queued 02:11
created

DependencyResolver::canBeCreatedByFactory()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 1
c 1
b 0
f 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Factory;
6
7
use Psr\Container\ContainerExceptionInterface;
8
use Psr\Container\ContainerInterface;
9
use Psr\Container\NotFoundExceptionInterface;
10
use Yiisoft\Factory\Definition\ArrayDefinition;
11
use Yiisoft\Factory\Definition\DefinitionInterface;
12
use Yiisoft\Factory\Definition\Normalizer;
13
use Yiisoft\Factory\Exception\InvalidConfigException;
14
use Yiisoft\Factory\Exception\NotFoundException;
15
use Yiisoft\Factory\Exception\NotInstantiableException;
16
17
use function is_object;
18
use function is_string;
19
20
/**
21
 * @internal
22
 */
23
final class DependencyResolver implements DependencyResolverInterface
24
{
25
    private ?ContainerInterface $container;
26
27
    /**
28
     * @var mixed[] Definitions
29
     * @psalm-var array<string, mixed>
30
     */
31
    private array $definitions = [];
32
33
    /**
34
     * @var DefinitionInterface[] object definitions indexed by their types
35
     * @psalm-var array<string, DefinitionInterface>
36
     */
37
    private array $definitionInstances = [];
38
39 73
    public function __construct(?ContainerInterface $container)
40
    {
41 73
        $this->container = $container;
42 73
    }
43
44
    /**
45
     * @param string $id
46
     *
47
     * @throws NotFoundExceptionInterface
48
     * @throws ContainerExceptionInterface
49
     *
50
     * @return mixed|object
51
     *
52
     * @psalm-suppress InvalidThrow
53
     */
54 18
    public function get($id)
55
    {
56 18
        if ($this->container !== null) {
57 9
            return $this->container->get($id);
58
        }
59 9
        return $this->getFromFactory($id);
60
    }
61
62
    /**
63
     * @param string $id
64
     */
65 2
    public function has($id): bool
66
    {
67 2
        if ($this->container !== null) {
68 1
            return $this->container->has($id);
69
        }
70 1
        return $this->canBeCreatedByFactory($id);
71
    }
72
73
    /**
74
     * @param string $id
75
     *
76
     * @throws InvalidConfigException
77
     * @throws NotFoundException
78
     * @throws NotInstantiableException
79
     *
80
     * @return mixed|object
81
     */
82 4
    public function resolve(string $id)
83
    {
84 4
        if (isset($this->definitions[$id])) {
85 2
            return $this->getFromFactory($id);
86
        }
87 3
        return $this->get($id);
88
    }
89
90 47
    public function shouldCloneOnResolve(): bool
91
    {
92 47
        return $this->container === null;
93
    }
94
95
    /**
96
     * @param mixed $definition
97
     */
98 39
    public function setFactoryDefinition(string $id, $definition): void
99
    {
100 39
        $this->definitions[$id] = $definition;
101 39
    }
102
103
    /**
104
     * @param mixed $config
105
     *
106
     * @throws InvalidConfigException
107
     */
108 36
    public function createDefinition($config): DefinitionInterface
109
    {
110 36
        if (is_string($config) && isset($this->definitions[$config])) {
111 12
            return Normalizer::normalize(
112 12
                is_object($this->definitions[$config])
113 3
                    ? clone $this->definitions[$config]
114 12
                    : $this->definitions[$config]
115
            );
116
        }
117
118 24
        $definition = Normalizer::normalize($config);
119
120
        if (
121 23
            ($definition instanceof ArrayDefinition) &&
122 23
            isset($this->definitions[$definition->getClass()])
123
        ) {
124 4
            $definition = $this->mergeDefinitions(
125 4
                $this->getDefinition($definition->getClass()),
126
                $definition
127
            );
128
        }
129
130 23
        return $definition;
131
    }
132
133
    /**
134
     * @param string $id
135
     *
136
     * @throws InvalidConfigException
137
     * @throws NotFoundException
138
     * @throws NotInstantiableException
139
     *
140
     * @return mixed|object
141
     */
142 10
    private function getFromFactory($id)
143
    {
144 10
        return $this->getDefinition($id)->resolve($this);
145
    }
146
147
    /**
148
     * @throws InvalidConfigException
149
     */
150 14
    private function getDefinition(string $id): DefinitionInterface
151
    {
152 14
        if (!isset($this->definitionInstances[$id])) {
153 14
            if (isset($this->definitions[$id])) {
154 8
                $this->definitionInstances[$id] = Normalizer::normalize($this->definitions[$id], $id);
155
            } else {
156
                /** @psalm-var class-string $id */
157 9
                $this->definitionInstances[$id] = ArrayDefinition::fromPreparedData($id);
158
            }
159
        }
160
161 14
        return $this->definitionInstances[$id];
162
    }
163
164 1
    private function canBeCreatedByFactory(string $id): bool
165
    {
166 1
        return isset($this->definitions[$id]) || class_exists($id);
167
    }
168
169 4
    private function mergeDefinitions(DefinitionInterface $one, ArrayDefinition $two): DefinitionInterface
170
    {
171 4
        return $one instanceof ArrayDefinition ? $one->merge($two) : $two;
172
    }
173
}
174