Passed
Push — master ( 083961...8c32c7 )
by butschster
08:05 queued 12s
created

DoctrineAnnotationReader   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 116
Duplicated Lines 0 %

Test Coverage

Coverage 72.09%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 38
c 1
b 0
f 0
dl 0
loc 116
ccs 31
cts 43
cp 0.7209
rs 10
wmc 19

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getPropertyMetadata() 0 5 1
A getConstantMetadata() 0 3 1
A checkAvailability() 0 7 2
A getParameterMetadata() 0 3 1
A wrapDoctrineExceptions() 0 21 6
A isAvailable() 0 3 1
A getClassMetadata() 0 8 2
A getFunctionMetadata() 0 9 2
A bootAnnotations() 0 5 2
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(fn () => $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

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

129
            /** @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...
130
        }
131
    }
132
133 252
    private function checkAvailability(): void
134
    {
135 252
        if ($this->isAvailable()) {
136 252
            return;
137
        }
138
139
        throw new InitializationException('Requires the "doctrine/annotations" package');
140
    }
141
}
142