Passed
Pull Request — master (#123)
by Sergei
06:25 queued 04:24
created

DependencyResolver::shouldCloneOnResolve()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

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 1
nc 1
nop 0
crap 1
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
use Yiisoft\Injector\Injector;
17
18
use function is_object;
19
use function is_string;
20
21
/**
22
 * @internal
23
 */
24
final class DependencyResolver implements DependencyResolverInterface
25
{
26
    private ?ContainerInterface $container;
27
    private ?Injector $injector = null;
28
29
    /**
30
     * @var mixed[] Definitions
31
     * @psalm-var array<string, mixed>
32
     */
33
    private array $definitions = [];
34
35
    /**
36
     * @var DefinitionInterface[] object definitions indexed by their types
37
     * @psalm-var array<string, DefinitionInterface>
38
     */
39
    private array $definitionInstances = [];
40
41 104
    public function __construct(?ContainerInterface $container)
42
    {
43 104
        $this->container = $container;
44 104
    }
45
46
    /**
47
     * @param string $id
48
     *
49
     * @throws NotFoundExceptionInterface
50
     * @throws ContainerExceptionInterface
51
     *
52
     * @return mixed|object
53
     *
54
     * @psalm-suppress InvalidThrow
55
     */
56 24
    public function get($id)
57
    {
58 24
        if ($this->container !== null) {
59 8
            return $this->container->get($id);
60
        }
61 16
        return $this->getFromFactory($id);
62
    }
63
64
    /**
65
     * @param string $id
66
     */
67 2
    public function has($id): bool
68
    {
69 2
        if ($this->container !== null) {
70 1
            return $this->container->has($id);
71
        }
72 1
        return $this->canBeCreatedByFactory($id);
73
    }
74
75
    /**
76
     * @param string $id
77
     *
78
     * @throws InvalidConfigException
79
     * @throws NotFoundException
80
     * @throws NotInstantiableException
81
     *
82
     * @return mixed|object
83
     */
84 26
    public function resolve(string $id)
85
    {
86 26
        return $this->getFromFactory($id);
87
    }
88
89
    /**
90
     * @return mixed
91
     */
92 14
    public function invoke(callable $callable)
93
    {
94 14
        return $this->getInjector()->invoke($callable);
95
    }
96
97 66
    public function shouldCloneOnResolve(): bool
98
    {
99 66
        return $this->container === null;
100
    }
101
102
    /**
103
     * @param mixed $definition
104
     */
105 75
    public function setFactoryDefinition(string $id, $definition): void
106
    {
107 75
        $this->definitions[$id] = $definition;
108 75
    }
109
110
    /**
111
     * @param mixed $config
112
     *
113
     * @throws InvalidConfigException
114
     */
115 67
    public function createDefinition($config): DefinitionInterface
116
    {
117 67
        if (is_string($config) && isset($this->definitions[$config])) {
118 38
            return Normalizer::normalize(
119 38
                is_object($this->definitions[$config])
120 9
                    ? clone $this->definitions[$config]
121 38
                    : $this->definitions[$config],
122
                $config
123
            );
124
        }
125
126 29
        $definition = Normalizer::normalize($config);
127
128
        if (
129 28
            ($definition instanceof ArrayDefinition) &&
130 28
            isset($this->definitions[$definition->getClass()])
131
        ) {
132 4
            $definition = $this->mergeDefinitions(
133 4
                $this->getDefinition($definition->getClass()),
134
                $definition
135
            );
136
        }
137
138 28
        return $definition;
139
    }
140
141
    /**
142
     * @param string $id
143
     *
144
     * @throws InvalidConfigException
145
     * @throws NotFoundException
146
     * @throws NotInstantiableException
147
     *
148
     * @return mixed|object
149
     */
150 32
    private function getFromFactory($id)
151
    {
152 32
        return $this->getDefinition($id)->resolve($this);
153
    }
154
155
    /**
156
     * @throws InvalidConfigException
157
     */
158 36
    private function getDefinition(string $id): DefinitionInterface
159
    {
160 36
        if (!isset($this->definitionInstances[$id])) {
161 36
            if (isset($this->definitions[$id])) {
162 24
                $this->definitionInstances[$id] = Normalizer::normalize($this->definitions[$id], $id);
163
            } else {
164
                /** @psalm-var class-string $id */
165 29
                $this->definitionInstances[$id] = ArrayDefinition::fromPreparedData($id);
166
            }
167
        }
168
169 36
        return $this->definitionInstances[$id];
170
    }
171
172 14
    private function getInjector(): Injector
173
    {
174 14
        if ($this->injector === null) {
175 14
            $this->injector = new Injector($this);
176
        }
177 14
        return $this->injector;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->injector could return the type null which is incompatible with the type-hinted return Yiisoft\Injector\Injector. Consider adding an additional type-check to rule them out.
Loading history...
178
    }
179
180 1
    private function canBeCreatedByFactory(string $id): bool
181
    {
182 1
        return isset($this->definitions[$id]) || class_exists($id);
183
    }
184
185 4
    private function mergeDefinitions(DefinitionInterface $one, ArrayDefinition $two): DefinitionInterface
186
    {
187 4
        return $one instanceof ArrayDefinition ? $one->merge($two) : $two;
188
    }
189
}
190