AnnotationDriver::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 7
ccs 4
cts 4
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. Annotations will be autoloaded in 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

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
     * @param class-string $classname
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
102
     *
103
     * @return array<ClassMetadata>
104
     */
105
    public function loadClassname(string $classname): array
106
    {
107 1
        $metadata = $this->getClassMetadataForClassname($classname);
108
109 1
        return $metadata ? [$metadata] : [];
110
    }
111
112
    /**
113
     * @param class-string $classname
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
114
     *
115
     * @throws \ReflectionException
116
     */
117
    private function getClassMetadataForClassname(
118
        string $classname
119
    ): ?ClassMetadata {
120 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

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