Passed
Pull Request — master (#756)
by Maxim
07:24
created

DoctrineAnnotationReader::getPropertyMetadata()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 2
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 1
rs 10
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of Spiral Framework package.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Spiral\Attributes\Internal;
13
14
use Doctrine\Common\Annotations\AnnotationException;
15
use Doctrine\Common\Annotations\AnnotationReader as DoctrineReader;
16
use Doctrine\Common\Annotations\AnnotationRegistry;
17
use Doctrine\Common\Annotations\Reader;
18
use Spiral\Attributes\Exception\AttributeException;
19
use Spiral\Attributes\Exception\InitializationException;
20
use Spiral\Attributes\Exception\SemanticAttributeException;
21
use Spiral\Attributes\Exception\SyntaxAttributeException;
22
use Spiral\Attributes\Reader as BaseReader;
23
24
final class DoctrineAnnotationReader extends BaseReader
25
{
26
    /**
27
     * @var Reader|null
28
     */
29
    private $reader;
30
31
    /**
32
     * @param Reader|null $reader
33
     */
34 252
    public function __construct(Reader $reader = null)
35
    {
36 252
        $this->checkAvailability();
37 252
        $this->bootAnnotations();
38
39 252
        $this->reader = $reader ?? new DoctrineReader();
40
    }
41
42
    /**
43
     * {@inheritDoc}
44
     */
45 65
    public function getClassMetadata(\ReflectionClass $class, string $name = null): iterable
46
    {
47 65
        $result = $this->wrapDoctrineExceptions(function () use ($class) {
48 65
            return $this->reader->getClassAnnotations($class);
0 ignored issues
show
Bug introduced by
The method getClassAnnotations() does not exist on null. ( Ignorable by Annotation )

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

48
            return $this->reader->/** @scrutinizer ignore-call */ getClassAnnotations($class);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
49
        });
50
51 65
        yield from $this->filter($name, $result);
52
53 65
        foreach ($class->getTraits() as $trait) {
54 56
            yield from $this->getClassMetadata($trait, $name);
55
        }
56
    }
57
58
    /**
59
     * {@inheritDoc}
60
     */
61 67
    public function getFunctionMetadata(\ReflectionFunctionAbstract $function, string $name = null): iterable
62
    {
63 67
        if ($function instanceof \ReflectionMethod) {
64 64
            $result = $this->wrapDoctrineExceptions(function () use ($function) {
65 64
                return $this->reader->getMethodAnnotations($function);
66
            });
67
68 64
            return $this->filter($name, $result);
69
        }
70
71 3
        return [];
72
    }
73
74
    /**
75
     * {@inheritDoc}
76
     */
77 55
    public function getPropertyMetadata(\ReflectionProperty $property, string $name = null): iterable
78
    {
79 55
        $result = $this->wrapDoctrineExceptions(function () use ($property) {
80 55
            return $this->reader->getPropertyAnnotations($property);
81
        });
82
83 55
        return $this->filter($name, $result);
84
    }
85
86
    /**
87
     * {@inheritDoc}
88
     */
89 3
    public function getConstantMetadata(\ReflectionClassConstant $constant, string $name = null): iterable
90
    {
91 3
        return [];
92
    }
93
94
    /**
95
     * {@inheritDoc}
96
     */
97 6
    public function getParameterMetadata(\ReflectionParameter $parameter, string $name = null): iterable
98
    {
99 6
        return [];
100
    }
101
102 252
    protected function isAvailable(): bool
103
    {
104 252
        return \interface_exists(Reader::class);
105
    }
106
107 105
    private function wrapDoctrineExceptions(\Closure $then): iterable
108
    {
109
        try {
110 105
            return $then();
111
        } catch (AnnotationException $e) {
112
            switch (true) {
113
                case \str_starts_with($e->getMessage(), '[Syntax Error]'):
114
                case \str_starts_with($e->getMessage(), '[Type Error]'):
115
                    $class = SyntaxAttributeException::class;
116
                    break;
117
118
                case \str_starts_with($e->getMessage(), '[Semantical Error]'):
119
                case \str_starts_with($e->getMessage(), '[Creation Error]'):
120
                    $class = SemanticAttributeException::class;
121
                    break;
122
123
                default:
124
                    $class = AttributeException::class;
125
            }
126
127
            throw new $class($e->getMessage(), $e->getCode(), $e);
128
        }
129
    }
130
131 252
    private function bootAnnotations(): void
132
    {
133
        // doctrine/annotations ^1.0 compatibility.
134 252
        if (\method_exists(AnnotationRegistry::class, 'registerLoader')) {
135 252
            AnnotationRegistry::registerLoader('\\class_exists');
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\Common\Annotati...istry::registerLoader() 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

135
            /** @scrutinizer ignore-deprecated */ AnnotationRegistry::registerLoader('\\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...
136
        }
137
    }
138
139 252
    private function checkAvailability(): void
140
    {
141 252
        if ($this->isAvailable()) {
142 252
            return;
143
        }
144
145
        throw new InitializationException('Requires the "doctrine/annotations" package');
146
    }
147
}
148