Completed
Push — master ( c6c9f9...5c331b )
by Miloš
01:45
created

Container::endResolving()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Laganica\Di;
4
5
use ArrayObject;
6
use InvalidArgumentException;
7
use Laganica\Di\Definition\ClassDefinition;
8
use Laganica\Di\Definition\DefinitionFactoryInterface;
9
use Laganica\Di\Definition\DefinitionInterface;
10
use Laganica\Di\Exception\CircularDependencyFoundException;
11
use Laganica\Di\Exception\ContainerException;
12
use Laganica\Di\Exception\DefinitionNotFoundException;
13
use Laganica\Di\Exception\InvalidDefinitionException;
14
use Laganica\Di\Exception\ClassNotFoundException;
15
use Laganica\Di\Resolver\ResolverFactoryInterface;
16
use Psr\Container\ContainerExceptionInterface;
17
use Psr\Container\ContainerInterface;
18
use Psr\Container\NotFoundExceptionInterface;
19
20
/**
21
 * Class Container
22
 *
23
 * @package Laganica\Di
24
 */
25
class Container implements ContainerInterface
26
{
27
    /**
28
     * @var ArrayObject
29
     */
30
    private $definitions;
31
32
    /**
33
     * @var ArrayObject
34
     */
35
    private $entries;
36
37
    /**
38
     * @var ArrayObject
39
     */
40
    private $resolving;
41
42
    /**
43
     * @var bool
44
     */
45
    private $autowire;
46
47
    /**
48
     * @var bool
49
     */
50
    private $annotations;
51
52
    /**
53
     * @var ResolverFactoryInterface
54
     */
55
    private $resolverFactory;
56
57
    /**
58
     * @var DefinitionFactoryInterface
59
     */
60
    private $definitionFactory;
61
62
    /**
63
     * @param DefinitionFactoryInterface $definitionFactory
64
     * @param ResolverFactoryInterface $resolverFactory
65
     */
66 19
    public function __construct(DefinitionFactoryInterface $definitionFactory, ResolverFactoryInterface $resolverFactory)
67
    {
68 19
        $this->definitions = new ArrayObject();
69 19
        $this->entries = new ArrayObject();
70 19
        $this->resolving = new ArrayObject();
71 19
        $this->definitionFactory = $definitionFactory;
72 19
        $this->resolverFactory = $resolverFactory;
73 19
        $this->resolverFactory->setContainer($this);
74 19
    }
75
76
    /**
77
     * @inheritDoc
78
     */
79 19
    public function get($id)
80
    {
81 19
        if (!is_string($id)) {
82 2
            $type = is_object($id) ? get_class($id) : gettype($id);
83 2
            throw new InvalidArgumentException("Argument \$id must be string, $type given");
84
        }
85
86 17
        if ($this->entries->offsetExists($id)) {
87 2
            return $this->entries->offsetGet($id);
88
        }
89
90 17
        $entry = $this->resolveEntry($id);
91 10
        $this->entries->offsetSet($id, $entry);
92
93 10
        return $entry;
94
    }
95
96
    /**
97
     * @inheritDoc
98
     */
99 3
    public function has($id): bool
100
    {
101
        try {
102 3
            $this->get($id);
103
104 1
            return true;
105 2
        } catch (NotFoundExceptionInterface $ex) {
106 1
            return false;
107 1
        } catch (ContainerExceptionInterface $ex) {
108 1
            return true;
109
        }
110
    }
111
112
    /**
113
     * @param string $id
114
     *
115
     * @throws CircularDependencyFoundException
116
     * @throws ClassNotFoundException
117
     * @throws ContainerException
118
     * @throws DefinitionNotFoundException
119
     * @throws InvalidDefinitionException
120
     *
121
     * @return mixed
122
     */
123 17
    private function resolveEntry(string $id)
124
    {
125 17
        $definition = $this->getDefinition($id);
126
127 15
        $this->startResolving($id);
128 15
        $entry = $this->resolverFactory->create($definition)->resolve($definition);
129 10
        $this->endResolving($id);
130
131 10
        return $entry;
132
    }
133
134
    /**
135
     * @param bool $autowire
136
     */
137 19
    public function setAutowire(bool $autowire): void
138
    {
139 19
        $this->autowire = $autowire;
140 19
    }
141
142 11
    private function isAutowireEnabled(): bool
143
    {
144 11
        return $this->autowire;
145
    }
146
147
    /**
148
     * @param bool $annotations
149
     */
150 19
    public function setAnnotations(bool $annotations): void
151
    {
152 19
        $this->annotations = $annotations;
153 19
    }
154
155
    /**
156
     * @return bool
157
     */
158 9
    public function areAnnotationsEnabled(): bool
159
    {
160 9
        return $this->annotations;
161
    }
162
163
    /**
164
     * @param ArrayObject $definitions
165
     */
166 19
    public function setDefinitions(ArrayObject $definitions): void
167
    {
168 19
        $this->definitions = $definitions;
169 19
    }
170
171
    /**
172
     * @param string $id
173
     *
174
     * @throws DefinitionNotFoundException
175
     * @throws InvalidDefinitionException
176
     *
177
     * @return DefinitionInterface
178
     */
179 17
    private function getDefinition(string $id): DefinitionInterface
180
    {
181 17
        $definition = $this->definitions->offsetExists($id)
182 13
            ? $this->definitions->offsetGet($id)
183 17
            : null;
184
185 17
        if ($definition === null && $this->isAutowireEnabled()) {
186 10
            $definition = new ClassDefinition($id);
187
        }
188
189 17
        if ($definition === null) {
190 1
            throw DefinitionNotFoundException::create($id);
191
        }
192
193 16
        return $this->definitionFactory->create($definition);
194
    }
195
196
    /**
197
     * @param string $id
198
     *
199
     * @throws CircularDependencyFoundException
200
     *
201
     * @return void
202
     */
203 15
    private function startResolving(string $id): void
204
    {
205 15
        if ($this->resolving->offsetExists($id)) {
206 1
            throw CircularDependencyFoundException::create($id);
207
        }
208
209 15
        $this->resolving->offsetSet($id, true);
210 15
    }
211
212
    /**
213
     * @param string $id
214
     *
215
     * @return void
216
     */
217 10
    private function endResolving(string $id): void
218
    {
219 10
        if ($this->resolving->offsetExists($id)) {
220 10
            $this->resolving->offsetUnset($id);
221
        }
222 10
    }
223
}
224