Completed
Push — master ( fab006...1c4cac )
by Miloš
01:47
created

Container::transformDefinition()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 0
loc 12
ccs 6
cts 6
cp 1
crap 3
rs 9.8666
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
        try {
76 7
            $definition = $this->getDefinition($id);
77
78 7
            if ($resolver = $this->resolverFactory->create($definition)) {
79 7
                return $this->addEntry($id, $resolver->resolve($definition));
80
            }
81 6
        } catch (DefinitionNotFoundException $ex) {
82 6
            if ($this->isAutowire()) {
83 6
                $resolver = $this->resolverFactory->createClassResolver();
84
85 6
                return $this->addEntry($id, $resolver->resolve(new ClassDefinition($id)));
86
            }
87
        }
88
89
        throw NotFoundException::create($id);
90
    }
91
92
    /**
93
     * @inheritDoc
94
     */
95
    public function has($id): bool
96
    {
97
        try {
98
            $this->get($id);
99
100
            return true;
101
        } catch (NotFoundExceptionInterface $ex) {
102
            return false;
103
        } catch (ContainerExceptionInterface $ex) {
104
            return true;
105
        }
106
    }
107
108
    /**
109
     * @param bool $autowire
110
     */
111 7
    public function setAutowire(bool $autowire): void
112
    {
113 7
        $this->autowire = $autowire;
114 7
    }
115
116 6
    public function isAutowire(): bool
117
    {
118 6
        return $this->autowire;
119
    }
120
121
    /**
122
     * @param array $definitions
123
     *
124
     * @throws ContainerException
125
     */
126 7
    public function addDefinitions(array $definitions): void
127
    {
128 7
        foreach ($definitions as $id => $definition) {
129 7
            $this->addDefinition($id, $definition);
130
        }
131 7
    }
132
133
    /**
134
     * @param string $id
135
     * @param $definition
136
     *
137
     * @throws ContainerException
138
     */
139 7
    public function addDefinition(string $id, $definition): void
140
    {
141 7
        if ($this->hasDefinition($id)) {
142
            throw new ContainerException("More than one definition is found for entry or class $id");
143
        }
144
145 7
        $this->definitions[$id] = $definition;
146 7
    }
147
148
    /**
149
     * @param string $id
150
     *
151
     * @throws DefinitionNotFoundException
152
     * @throws InvalidDefinitionException
153
     *
154
     * @return DefinitionInterface
155
     */
156 7
    public function getDefinition(string $id): DefinitionInterface
157
    {
158 7
        $definition = $this->definitions[$id] ?? null;
159
160 7
        if ($definition === null) {
161 6
            throw DefinitionNotFoundException::create($id);
162
        }
163
164 7
        return $this->definitionFactory->create($definition);
165
    }
166
167
    /**
168
     * @param string $id
169
     *
170
     * @return bool
171
     */
172 7
    public function hasDefinition(string $id): bool
173
    {
174 7
        return array_key_exists($id, $this->definitions);
175
    }
176
177
    /**
178
     * @param string $id
179
     * @param mixed $entry
180
     *
181
     * @return mixed
182
     */
183 7
    private function addEntry(string $id, $entry)
184
    {
185 7
        return $this->entries[$id] = $entry;
186
    }
187
188
    /**
189
     * @param string $id
190
     *
191
     * @return null|mixed
192
     */
193 7
    public function getEntry(string $id)
194
    {
195 7
        return $this->entries[$id] ?? null;
196
    }
197
}
198