Passed
Push — master ( 9063de...1d7141 )
by Dawid
03:17
created

AnnotationMetaDataFactory::parseProperties()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 7
cts 7
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 6
nc 4
nop 2
crap 4
1
<?php declare(strict_types=1);
2
3
namespace Igni\Storage\Mapping\MetaData\Strategy;
4
5
use Cache\Adapter\PHPArray\ArrayCachePool;
6
use Doctrine\Common\Annotations\Annotation;
7
use Doctrine\Common\Annotations\AnnotationReader;
8
use Doctrine\Common\Annotations\AnnotationRegistry;
9
use Doctrine\Common\Annotations\IndexedReader;
10
use Doctrine\Common\Annotations\Reader;
11
use Igni\Storage\Exception\MappingException;
12
use Igni\Storage\Mapping\Annotations\EmbeddedEntity;
13
use Igni\Storage\Mapping\Annotations\Entity;
14
use Igni\Storage\Mapping\Annotations;
15
use Igni\Storage\Mapping\MetaData\EntityMetaData;
16
use Igni\Storage\Mapping\MetaData\MetaDataFactory;
17
use Igni\Storage\Mapping\MetaData\PropertyMetaData;
18
use Igni\Storage\Mapping\Type;
19
use Igni\Utils\ReflectionApi;
20
use Psr\SimpleCache\CacheInterface;
21
use ReflectionProperty;
22
use ReflectionClass;
23
24
class AnnotationMetaDataFactory implements MetaDataFactory
25
{
26
    /**
27
     * @var CacheInterface
28
     */
29
    private $cache;
30
31
    /**
32
     * @var Reader
33
     */
34
    private $reader;
35
36 31
    public function __construct(CacheInterface $cache = null)
37
    {
38 31
        AnnotationRegistry::registerUniqueLoader('class_exists');
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\Common\Annotati...:registerUniqueLoader() has been deprecated: this method is deprecated and will be removed in doctrine/annotations 2.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

38
        /** @scrutinizer ignore-deprecated */ AnnotationRegistry::registerUniqueLoader('class_exists');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
39 31
        $this->reader = new IndexedReader(new AnnotationReader());
40
41 31
        if ($cache === null) {
42 31
            $cache = new ArrayCachePool();
43
        }
44
45 31
        $this->cache = $cache;
46 31
    }
47
48 19
    public function getMetaData(string $entity): EntityMetaData
49
    {
50 19
        $cacheKey = str_replace('\\', '', $entity) . '.metadata';
51 19
        if ($this->cache->has($cacheKey)) {
52
            return $this->cache->get($cacheKey);
53
        }
54
55 19
        $metaData = $this->parseMetaData($entity);
56 19
        $this->cache->set($cacheKey, $metaData);
57
58 19
        return $metaData;
59
    }
60
61 19
    protected function parseMetaData(string $entityClass): EntityMetaData
62
    {
63 19
        $metaData = new EntityMetaData($entityClass);
64 19
        $reflection = ReflectionApi::reflectClass($entityClass);
65
66 19
        $this->parseClassAnnotations($reflection, $metaData);
67 19
        $this->parseProperties($reflection, $metaData);
68
69 19
        return $metaData;
70
    }
71
72 19
    private function parseClassAnnotations(ReflectionClass $reflection, EntityMetaData $metaData): void
73
    {
74 19
        $classAnnotations = $this->reader->getClassAnnotations($reflection);
75
76 19
        foreach ($classAnnotations as $type => $annotation) {
77
            switch ($type) {
78 19
                case Entity::class:
79 19
                    $source = $annotation->source ?? $annotation->value;
80 19
                    $metaData->setSource($source);
81 19
                    $this->setCustomHydrator($annotation, $metaData);
82 19
                    break;
83 3
                case EmbeddedEntity::class:
84 3
                    $metaData->makeEmbed();
85 3
                    $this->setCustomHydrator($annotation, $metaData);
86 19
                    break;
87
            }
88
        }
89 19
    }
90
91 19
    private function parseProperties(ReflectionClass $reflection, EntityMetaData $metaData): void
92
    {
93 19
        foreach ($reflection->getProperties() as $property) {
94 19
            $annotations = $this->reader->getPropertyAnnotations($property);
95 19
            foreach ($annotations as $annotation) {
96 19
                if ($annotation instanceof Annotations\Type) {
97 19
                    $this->addProperty($property, $annotation, $metaData);
98 19
                    break;
99
                }
100
            }
101
        }
102 19
    }
103
104 19
    private function setCustomHydrator(Annotation $annotation, EntityMetaData $metaData)
105
    {
106 19
        if ($annotation->hydrator !== null) {
107 18
            if (!class_exists($annotation->hydrator)) {
108
                throw new MappingException("Cannot use hydrator {$annotation->hydrator} class does not exist.");
109
            }
110
111 18
            $metaData->setCustomHydratorClass($annotation->hydrator);
112
        }
113 19
    }
114
115 19
    private function addProperty(ReflectionProperty $property, Annotations\Type $annotation, EntityMetaData $metaData): void
116
    {
117 19
        if (!Type::has($annotation->getType())) {
118
            throw new MappingException("Cannot map property {$property->getDeclaringClass()->getName()}::{$property->getName()} - unknown type {$annotation->getType()}.");
119
        }
120
121 19
        $property = new PropertyMetaData(
122 19
            $property->getName(),
123 19
            Type::get($annotation->getType())
124
        );
125 19
        $property->setFieldName($annotation->name ?? $property->getName());
126 19
        $property->setAttributes($annotation->getAttributes());
127 19
        $metaData->addProperty($property);
128 19
    }
129
}
130