Passed
Pull Request — master (#656)
by Abdul Malik
11:30 queued 05:15
created

DoctrineAnnotationReader::checkAvailability()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 7
ccs 3
cts 4
cp 0.75
crap 2.0625
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 ReflectionClass;
15
use ReflectionFunctionAbstract;
16
use ReflectionMethod;
17
use ReflectionProperty;
18
use ReflectionClassConstant;
19
use ReflectionParameter;
20
use Closure;
21
use Doctrine\Common\Annotations\AnnotationException;
22
use Doctrine\Common\Annotations\AnnotationReader as DoctrineReader;
23
use Doctrine\Common\Annotations\AnnotationRegistry;
24
use Doctrine\Common\Annotations\Reader;
25
use Spiral\Attributes\Exception\AttributeException;
26
use Spiral\Attributes\Exception\InitializationException;
27
use Spiral\Attributes\Exception\SemanticAttributeException;
28
use Spiral\Attributes\Exception\SyntaxAttributeException;
29
use Spiral\Attributes\Reader as BaseReader;
30
31
final class DoctrineAnnotationReader extends BaseReader
32
{
33
    private ?\Doctrine\Common\Annotations\Reader $reader = null;
34
35
    /**
36
     * @param Reader|null $reader
37
     */
38 240
    public function __construct(Reader $reader = null)
39
    {
40 240
        $this->checkAvailability();
41 240
        $this->bootAnnotations();
42
43 240
        $this->reader = $reader ?? new DoctrineReader();
44
    }
45
46
    /**
47
     * {@inheritDoc}
48
     */
49 57
    public function getClassMetadata(ReflectionClass $class, string $name = null): iterable
50
    {
51 57
        $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

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

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