Passed
Pull Request — master (#93)
by Julien
02:39
created

AnnotationDriver::getPropertyAnnotation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 8
ccs 3
cts 3
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Mapado\RestClientSdk\Mapping\Driver;
6
7
use Doctrine\Common\Annotations\AnnotationReader;
8
use Doctrine\Common\Annotations\AnnotationRegistry;
9
use Doctrine\Common\Annotations\FileCacheReader;
10
use Doctrine\Common\Annotations\Reader;
11
use Mapado\RestClientSdk\Exception\MappingException;
12
use Mapado\RestClientSdk\Mapping\Annotations;
13
use Mapado\RestClientSdk\Mapping\Attribute;
14
use Mapado\RestClientSdk\Mapping\ClassMetadata;
15
use Mapado\RestClientSdk\Mapping\Relation;
16
17
/**
18
 * Class AnnotationDriver
19
 *
20
 * @author Julien Deniau <[email protected]>
21
 */
22
class AnnotationDriver
23
{
24
    /**
25
     * @var string
26
     */
27
    private $cachePath;
28
29
    /**
30
     * @var bool
31
     */
32
    private $debug;
33
34
    public function __construct(string $cachePath, bool $debug = false)
35
    {
36 1
        $this->cachePath = $cachePath;
37 1
        $this->debug = $debug;
38
39 1
        AnnotationRegistry::registerFile(
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\Common\Annotati...egistry::registerFile() has been deprecated: this method is deprecated and will be removed in doctrine/annotations 2.0 autoloading should be deferred to the globally registered autoloader by then. For now, use @example AnnotationRegistry::registerLoader('class_exists') ( Ignorable by Annotation )

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

39
        /** @scrutinizer ignore-deprecated */ AnnotationRegistry::registerFile(

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...
40 1
            __DIR__ . '/../Annotations/AllAnnotations.php'
41
        );
42 1
    }
43
44
    /**
45
     * @return array<ClassMetadata>
46
     *
47
     * @throws MappingException
48
     */
49
    public function loadDirectory(string $path): array
50
    {
51 1
        if (!is_dir($path)) {
52
            throw new MappingException($path . ' is not a valid directory');
53
        }
54
55 1
        $iterator = new \RegexIterator(
56 1
            new \RecursiveIteratorIterator(
57 1
                new \RecursiveDirectoryIterator(
58 1
                    $path,
59 1
                    \FilesystemIterator::SKIP_DOTS
60
                ),
61 1
                \RecursiveIteratorIterator::LEAVES_ONLY
62
            ),
63 1
            '/^.+\.php$/i',
64 1
            \RecursiveRegexIterator::GET_MATCH
65
        );
66
67 1
        $classes = [];
68 1
        $includedFiles = [];
69
70 1
        foreach ($iterator as $file) {
71 1
            $sourceFile = $file[0];
72 1
            if (!preg_match('(^phar:)i', $sourceFile)) {
73 1
                $sourceFile = realpath($sourceFile);
74
            }
75
76 1
            require_once $sourceFile;
77 1
            $includedFiles[] = $sourceFile;
78
        }
79
80 1
        $declared = get_declared_classes();
81 1
        foreach ($declared as $className) {
82 1
            $rc = new \ReflectionClass($className);
83 1
            $sourceFile = $rc->getFileName();
84 1
            if (in_array($sourceFile, $includedFiles)) {
85 1
                $classes[] = $className;
86
            }
87
        }
88
89 1
        $mapping = [];
90 1
        foreach ($classes as $class) {
91 1
            $metadata = $this->getClassMetadataForClassname($class);
92 1
            if ($metadata) {
93 1
                $mapping[] = $metadata;
94
            }
95
        }
96
97 1
        return $mapping;
98
    }
99
100
    /**
101
     * @return array<ClassMetadata>
102
     */
103
    public function loadClassname(string $classname): array
104
    {
105 1
        $metadata = $this->getClassMetadataForClassname($classname);
106
107 1
        return $metadata ? [$metadata] : [];
108
    }
109
110
    private function getClassMetadataForClassname(
111
        string $classname
112
    ): ?ClassMetadata {
113 1
        $reader = new FileCacheReader(
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\Common\Annotations\FileCacheReader has been deprecated: the FileCacheReader is deprecated and will be removed in version 2.0.0 of doctrine/annotations. Please use the {@see \Doctrine\Common\Annotations\CachedReader} instead. ( Ignorable by Annotation )

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

113
        $reader = /** @scrutinizer ignore-deprecated */ new FileCacheReader(
Loading history...
114 1
            new AnnotationReader(),
115 1
            $this->cachePath,
116 1
            $this->debug
117
        );
118
119 1
        $reflClass = new \ReflectionClass($classname);
120
        /** @var Annotations\Entity|null */
121 1
        $classAnnotation = $reader->getClassAnnotation(
122 1
            $reflClass,
123 1
            Annotations\Entity::class
124
        );
125
126 1
        if (!$classAnnotation) {
127 1
            return null;
128
        }
129
130 1
        $attributeList = [];
131 1
        $relationList = [];
132 1
        foreach ($reflClass->getProperties() as $property) {
133
            // manage attributes
134
            /** @var Annotations\Attribute|null */
135 1
            $propertyAnnotation = $this->getPropertyAnnotation(
136 1
                $reader,
137
                $property,
138 1
                'Attribute'
139
            );
140
141 1
            if ($propertyAnnotation) {
142 1
                $isId = $this->getPropertyAnnotation($reader, $property, 'Id');
143
144 1
                $attributeList[] = new Attribute(
145 1
                    $propertyAnnotation->name,
146 1
                    $property->getName(),
147 1
                    $propertyAnnotation->type,
148 1
                    (bool) $isId
149
                );
150
            } else {
151
                // manage relations
152
                /** @var Annotations\OneToMany|null */
153 1
                $relation = $this->getPropertyAnnotation(
154 1
                    $reader,
155
                    $property,
156 1
                    'OneToMany'
157
                );
158 1
                if (!$relation) {
159
                    /** @var Annotations\ManyToOne|null */
160 1
                    $relation = $this->getPropertyAnnotation(
161 1
                        $reader,
162
                        $property,
163 1
                        'ManyToOne'
164
                    );
165
                }
166
167 1
                if ($relation) {
168 1
                    $attributeList[] = new Attribute(
169 1
                        $relation->name,
170 1
                        $property->getName()
171
                    );
172
173 1
                    $targetEntity = $relation->targetEntity;
174 1
                    if (false === mb_strpos($targetEntity, '/')) {
175
                        $targetEntity =
176 1
                            mb_substr(
177 1
                                $classname,
178 1
                                0,
179 1
                                mb_strrpos($classname, '\\') + 1
180 1
                            ) . $targetEntity;
181
                    }
182
183 1
                    $relationList[] = new Relation(
184 1
                        $relation->name,
185 1
                        $relation->type,
186
                        $targetEntity
187
                    );
188
                }
189
            }
190
        }
191
192 1
        $classMetadata = new ClassMetadata(
193 1
            $classAnnotation->key,
194
            $classname,
195 1
            $classAnnotation->repository
196
        );
197 1
        $classMetadata->setAttributeList($attributeList);
198 1
        $classMetadata->setRelationList($relationList);
199
200 1
        return $classMetadata;
201
    }
202
203
    private function getPropertyAnnotation(
204
        Reader $reader,
205
        \ReflectionProperty $property,
206
        string $classname
207
    ): ?object {
208 1
        return $reader->getPropertyAnnotation(
209 1
            $property,
210 1
            'Mapado\\RestClientSdk\\Mapping\\Annotations\\' . $classname
211
        );
212
    }
213
}
214