Completed
Push — master ( 6366df...fbe022 )
by Kirill
23s queued 19s
created

DoctrineAnnotationReader::wrapDoctrineExceptions()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 15
c 1
b 0
f 0
nc 6
nop 1
dl 0
loc 21
rs 9.2222
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
    public function __construct(Reader $reader = null)
35
    {
36
        $this->checkAvailability();
37
        $this->bootAnnotations();
38
39
        $this->reader = $reader ?? new DoctrineReader();
40
    }
41
42
    /**
43
     * {@inheritDoc}
44
     */
45
    public function getClassMetadata(\ReflectionClass $class, string $name = null): iterable
46
    {
47
        $result = $this->wrapDoctrineExceptions(function () use ($class) {
48
            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
        return $this->filter($name, $result);
52
    }
53
54
    /**
55
     * {@inheritDoc}
56
     */
57
    public function getFunctionMetadata(\ReflectionFunctionAbstract $function, string $name = null): iterable
58
    {
59
        if ($function instanceof \ReflectionMethod) {
60
            $result = $this->wrapDoctrineExceptions(function () use ($function) {
61
                return $this->reader->getMethodAnnotations($function);
62
            });
63
64
            return $this->filter($name, $result);
65
        }
66
67
        return [];
68
    }
69
70
    /**
71
     * {@inheritDoc}
72
     */
73
    public function getPropertyMetadata(\ReflectionProperty $property, string $name = null): iterable
74
    {
75
        $result = $this->wrapDoctrineExceptions(function () use ($property) {
76
            return $this->reader->getPropertyAnnotations($property);
77
        });
78
79
        return $this->filter($name, $result);
80
    }
81
82
    /**
83
     * {@inheritDoc}
84
     */
85
    public function getConstantMetadata(\ReflectionClassConstant $constant, string $name = null): iterable
86
    {
87
        return [];
88
    }
89
90
    /**
91
     * {@inheritDoc}
92
     */
93
    public function getParameterMetadata(\ReflectionParameter $parameter, string $name = null): iterable
94
    {
95
        return [];
96
    }
97
98
    /**
99
     * @return bool
100
     */
101
    protected function isAvailable(): bool
102
    {
103
        return \interface_exists(Reader::class);
104
    }
105
106
    private function wrapDoctrineExceptions(\Closure $then): iterable
107
    {
108
        try {
109
            return $then();
110
        } catch (AnnotationException $e) {
111
            switch (true) {
112
                case \str_starts_with($e->getMessage(), '[Syntax Error]'):
113
                case \str_starts_with($e->getMessage(), '[Type Error]'):
114
                    $class = SyntaxAttributeException::class;
115
                    break;
116
117
                case \str_starts_with($e->getMessage(), '[Semantical Error]'):
118
                case \str_starts_with($e->getMessage(), '[Creation Error]'):
119
                    $class = SemanticAttributeException::class;
120
                    break;
121
122
                default:
123
                    $class = AttributeException::class;
124
            }
125
126
            throw new $class($e->getMessage(), (int)$e->getCode(), $e);
127
        }
128
    }
129
130
    /**
131
     * @return void
132
     */
133
    private function bootAnnotations(): void
134
    {
135
        // doctrine/annotations ^1.0 compatibility.
136
        if (\method_exists(AnnotationRegistry::class, 'registerLoader')) {
137
            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

137
            /** @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...
138
        }
139
    }
140
141
    /**
142
     * @return void
143
     */
144
    private function checkAvailability(): void
145
    {
146
        if ($this->isAvailable()) {
147
            return;
148
        }
149
150
        throw new InitializationException('Requires the "doctrine/annotations" package');
151
    }
152
}
153