Completed
Push — master ( 2bdb69...583647 )
by Dawid
04:42
created

AnnotationMetaDataFactory::parseMetaData()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 9
ccs 6
cts 6
cp 1
crap 1
rs 10
c 0
b 0
f 0
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\Annotation\EmbeddedEntity;
13
use Igni\Storage\Mapping\Annotation\Entity;
14
use Igni\Storage\Mapping\Annotation\Property as Property;
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 51
    public function __construct(CacheInterface $cache = null)
37
    {
38 51
        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 51
        $this->reader = new IndexedReader(new AnnotationReader());
40
41 51
        if ($cache === null) {
42 51
            $cache = new ArrayCachePool();
43
        }
44
45 51
        $this->cache = $cache;
46 51
    }
47
48
    /**
49
     * @param string $entity
50
     * @return EntityMetaData
51
     */
52 23
    public function getMetaData(string $entity): EntityMetaData
53
    {
54
        try {
55 23
            $metaData = new EntityMetaData($entity);
56 23
            $reflection = ReflectionApi::reflectClass($entity);
57
        } catch (\ReflectionException $e) {
58
            throw MappingException::forInvalidEntityClass($entity);
59
        }
60
61 23
        $this->parseClassAnnotations($reflection, $metaData);
62 23
        $this->parseProperties($reflection, $metaData);
63
64 23
        return $metaData;
65
    }
66
67 23
    private function parseClassAnnotations(ReflectionClass $reflection, EntityMetaData $metaData): void
68
    {
69 23
        $classAnnotations = $this->reader->getClassAnnotations($reflection);
70
71 23
        foreach ($classAnnotations as $type => $annotation) {
72
            switch ($type) {
73 23
                case Entity::class:
74 23
                    $source = $annotation->source ?? $annotation->value;
75 23
                    $metaData->setSource($source);
76 23
                    $metaData->setConnection($annotation->connection);
77 23
                    $this->setCustomHydrator($annotation, $metaData);
78 23
                    break;
79 3
                case EmbeddedEntity::class:
80 3
                    $metaData->makeEmbed();
81 3
                    $this->setCustomHydrator($annotation, $metaData);
82 23
                    break;
83
            }
84
        }
85 23
    }
86
87 23
    private function parseProperties(ReflectionClass $reflection, EntityMetaData $metaData): void
88
    {
89 23
        foreach ($reflection->getProperties() as $property) {
90 23
            $annotations = $this->reader->getPropertyAnnotations($property);
91 23
            foreach ($annotations as $annotation) {
92 23
                if ($annotation instanceof Property) {
93 23
                    $this->addProperty($property, $annotation, $metaData);
94 23
                    break;
95
                }
96
            }
97
        }
98
99 23
        if (!$metaData->definesProperties()) {
100
            throw MappingException::forEmptyMapping($metaData->getClass());
101
        }
102 23
    }
103
104
    /**
105
     * @param EmbeddedEntity|Entity|Annotation $annotation
106
     * @param EntityMetaData $metaData
107
     */
108 23
    private function setCustomHydrator(Annotation $annotation, EntityMetaData $metaData)
109
    {
110 23
        if ($annotation->hydrator !== null) {
111 22
            if (!class_exists($annotation->hydrator)) {
112
                throw new MappingException("Cannot use hydrator {$annotation->hydrator} class does not exist.");
113
            }
114
115
            /** @noinspection PhpStrictTypeCheckingInspection */
116 22
            $metaData->setCustomHydratorClass($annotation->hydrator);
117
        }
118 23
    }
119
120 23
    private function addProperty(ReflectionProperty $property, Property $annotation, EntityMetaData $metaData): void
121
    {
122 23
        if (!Type::has($annotation->getType())) {
123
            throw new MappingException("Cannot map property {$property->getDeclaringClass()->getName()}::{$property->getName()} - unknown type {$annotation->getType()}.");
124
        }
125
126 23
        $property = new PropertyMetaData(
127 23
            $property->getName(),
128 23
            Type::get($annotation->getType())
129
        );
130 23
        $property->setFieldName($annotation->name ?? $property->getName());
131 23
        $property->setAttributes($annotation->getAttributes());
132 23
        $metaData->addProperty($property);
133 23
    }
134
}
135