EntityManager::addRepository()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Igni\Storage;
4
5
use Cache\Adapter\PHPArray\ArrayCachePool;
6
use Igni\Storage\Exception\HydratorException;
7
use Igni\Storage\Exception\RepositoryException;
8
use Igni\Storage\Hydration\HydratorAutoGenerate;
9
use Igni\Storage\Hydration\HydratorFactory;
10
use Igni\Storage\Hydration\ObjectHydrator;
11
use Igni\Storage\Mapping\IdentityMap;
12
use Igni\Storage\Mapping\MetaData\EntityMetaData;
13
use Igni\Storage\Mapping\MetaData\MetaDataFactory;
14
use Igni\Storage\Mapping\MetaData\Strategy\AnnotationMetaDataFactory;
15
use Psr\SimpleCache\CacheInterface;
16
17
class EntityManager implements IdentityMap, MetaDataFactory
18
{
19
    /** @var Storable[] */
20
    private $registry = [];
21
22
    /** @var Repository[] */
23
    private $repositories = [];
24
25
    /** @var HydratorFactory */
26
    private $hydratorFactory;
27
28
    /** @var ObjectHydrator[] */
29
    private $hydrators = [];
30
31
    /** @var MetaDataFactory */
32
    private $metaDataFactory;
33
34
    /** @var string */
35
    private $hydratorDir;
36
37
    /** @var string */
38
    private $hydratorNamespace;
39
40
    /** @var CacheInterface */
41
    private $cache;
42
43
    /**
44
     * EntityManager constructor.
45
     * @param string|null $hydratorDir
46
     * @param string|null $hydratorNamespace
47
     * @param string|null $hydratorAutoGenerate
48
     * @param CacheInterface|null $cache
49
     * @param MetaDataFactory|null $metaDataFactory
50
     */
51 49
    public function __construct(
52
        string $hydratorDir = null,
53
        string $hydratorNamespace = null,
54
        string $hydratorAutoGenerate = HydratorAutoGenerate::IF_NOT_EXISTS,
55
        CacheInterface $cache = null,
56
        MetaDataFactory $metaDataFactory = null
57
    ) {
58 49
        if ($hydratorDir === null) {
59 4
            $hydratorDir = sys_get_temp_dir();
60
        }
61
62 49
        if (!is_writable($hydratorDir)) {
63
            throw new HydratorException("Hydrators cannot be generated, directory ($hydratorDir) is not writable.");
64
        }
65
66 49
        if ($metaDataFactory === null) {
67 49
            $metaDataFactory = new AnnotationMetaDataFactory();
68
        }
69
70 49
        if ($cache === null) {
71 49
            $cache = new ArrayCachePool();
72
        }
73
74 49
        $this->cache = $cache;
75 49
        $this->hydratorDir = $hydratorDir;
76 49
        $this->metaDataFactory = $metaDataFactory;
77 49
        $this->hydratorNamespace = $hydratorNamespace ?? '';
78 49
        $this->hydratorFactory = new HydratorFactory($this, $hydratorAutoGenerate);
79 49
    }
80
81 2
    public function getHydratorDir(): string
82
    {
83 2
        return $this->hydratorDir;
84
    }
85
86 22
    public function getHydratorNamespace(): string
87
    {
88 22
        return $this->hydratorNamespace;
89
    }
90
91
    /**
92
     * Creates new entity in the storage.
93
     *
94
     * @param Storable $entity
95
     * @return Storable
96
     */
97 2
    public function create(Storable $entity): Storable
98
    {
99 2
        $this->getRepository(get_class($entity))->create($entity);
100 2
        $this->attach($entity);
101
102 2
        return $entity;
103
    }
104
105
    /**
106
     * Updated entity in the storage.
107
     *
108
     * @param Storable $entity
109
     * @return Storable
110
     */
111 1
    public function update(Storable $entity): Storable
112
    {
113 1
        $this->getRepository(get_class($entity))->update($entity);
114
115 1
        return $entity;
116
    }
117
118
    /**
119
     * Removes entity from the storage.
120
     *
121
     * @param Storable $entity
122
     * @return Storable
123
     */
124 2
    public function remove(Storable $entity): Storable
125
    {
126 2
        $this->getRepository(get_class($entity))->remove($entity);
127 2
        $this->detach($entity);
128
129 2
        return $entity;
130
    }
131
132
    /**
133
     * Retrieves entity by identifier from the storage.
134
     *
135
     * @param string $entity
136
     * @param $id
137
     * @return Storable
138
     */
139 11
    public function get(string $entity, $id): Storable
140
    {
141 11
        $key = $this->getId($entity, $id);
142
143 11
        if ($this->has($entity, $id)) {
144 1
            return $this->registry[$key];
145
        }
146
147 11
        return $this->getRepository($entity)->get($id);
148
    }
149
150 14
    public function getRepository(string $entity): Repository
151
    {
152 14
        if ($this->hasRepository($entity)) {
153 14
            return $this->repositories[$entity];
154
        }
155
156
        throw RepositoryException::forNotRegisteredRepository($entity);
157
    }
158
159 14
    public function hasRepository(string $entity): bool
160
    {
161 14
        return isset($this->repositories[$entity]);
162
    }
163
164 22
    public function addRepository(Repository ...$repositories): void
165
    {
166 22
        foreach ($repositories as $repository) {
167 22
            $this->repositories[$repository::getEntityClass()] = $repository;
168
        }
169 22
    }
170
171 12
    public function attach(Storable $entity): Storable
172
    {
173 12
        $key = $this->getId($entity);
174
175 12
        if (!isset($this->registry[$key])) {
176 12
            $this->registry[$key] = $entity;
177
        }
178
179 12
        return $this->registry[$key];
180
    }
181
182 3
    public function detach(Storable $entity): Storable
183
    {
184 3
        $key = $this->getId($entity);
185 3
        if (isset($this->registry[$key])) {
186 3
            unset($this->registry[$key]);
187
        }
188
189 3
        return $entity;
190
    }
191
192
    /**
193
     *
194
     * @param string $class
195
     * @param $id
196
     * @return bool
197
     */
198 13
    public function has(string $class, $id): bool
199
    {
200 13
        $key = $this->getId($class, $id);
201 13
        return isset($this->registry[$key]);
202
    }
203
204
    /**
205
     * Checks if entity lives in the identity map.
206
     *
207
     * @param Storable $entity
208
     * @return bool
209
     */
210 3
    public function contains(Storable $entity): bool
211
    {
212 3
        return in_array($entity, $this->registry, true);
213
    }
214
215
    /**
216
     * Clears identity map.
217
     */
218 1
    public function clear(): void
219
    {
220 1
        $this->registry = [];
221 1
    }
222
223
    /**
224
     * Gets global id for entity which is used for
225
     * later storage in the identity map.
226
     *
227
     * @param $entity
228
     * @param null $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
229
     * @return string
230
     */
231 14
    private function getId($entity, $id = null): string
232
    {
233 14
        if ($entity instanceof Storable) {
234 12
            return get_class($entity) . '@' . $entity->getId()->getValue();
235
        }
236
237
        return "${entity}@${id}";
238
    }
239
240
    /**
241
     * Creates instance of the entity class and hydrates it with passed data.
242
     *
243
     * @param string $entityClass
244
     * @param array $data
245
     * @return object
246
     */
247
    public function hydrate(string $entityClass, array $data)
248
    {
249 2
        $hydrator = $this->getHydrator($entityClass);
250
251 2
        return $hydrator->hydrate($data);
252
    }
253
254
    /**
255
     * Extracts data from passed entity and returns it.
256
     *
257
     * @param $entity
258
     * @return array
259
     */
260
    public function extract($entity): array
261
    {
262 1
        $entityClass = get_class($entity);
263
264 1
        $hydrator = $this->getHydrator($entityClass);
265
266 1
        return $hydrator->extract($entity);
267
    }
268
269
    /**
270
     * Returns hydrator for the given entity.
271
     *
272
     * @param string $entity
273
     * @return ObjectHydrator
274
     */
275
    public function getHydrator(string $entity): ObjectHydrator
276
    {
277 22
        if (!isset($this->hydrators[$entity])) {
278 22
            $this->hydrators[$entity] = $this->hydratorFactory->get($entity);
279
        }
280
281 22
        return $this->hydrators[$entity];
282
    }
283
284
    /**
285
     * Returns entity's mapping metadata information
286
     *
287
     * @param string $entity
288
     * @return EntityMetaData
289
     */
290
    public function getMetaData(string $entity): EntityMetaData
291
    {
292 22
        $key = str_replace('\\', '.', $entity) . '.metadata';
293
294 22
        if (!$this->cache->has($key)) {
295 22
            $metaData = $this->metaDataFactory->getMetaData($entity);
296 22
            $this->cache->set($key, $metaData);
297
298 22
            return $metaData;
299
        }
300
301 22
        return $this->cache->get($key);
302
    }
303
}
304