Completed
Push — master ( 1c4cac...3cc274 )
by Miloš
01:09
created

Container::resolveEntry()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

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