Failed Conditions
Push — master ( 05fc61...964283 )
by Adrien
02:24
created

Reader   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 86
Duplicated Lines 0 %

Test Coverage

Coverage 92.59%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 11
eloc 25
c 1
b 0
f 0
dl 0
loc 86
rs 10
ccs 25
cts 27
cp 0.9259

4 Methods

Rating   Name   Duplication   Size   Complexity  
A onlyOne() 0 7 3
A getRecursiveClassAttributes() 0 19 4
A getAttributeInstances() 0 17 3
A getAttribute() 0 5 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Doctrine\Attribute\Reader;
6
7
use GraphQL\Doctrine\Attribute\ApiAttribute;
8
use GraphQL\Doctrine\Exception;
9
use ReflectionClass;
10
use ReflectionMethod;
11
use ReflectionParameter;
12
use ReflectionProperty;
13
14
/**
15
 * API attribute reader.
16
 */
17
final class Reader
18
{
19
    /**
20
     * Return an array of all attributes found in the class hierarchy, including its traits, indexed by the class name.
21
     *
22
     * @template T of ApiAttribute
23
     *
24
     * @param class-string<T> $attributeName
25
     *
26
     * @return array<class-string, T[]> attributes indexed by the class name where they were found
1 ignored issue
show
Documentation Bug introduced by
The doc comment array<class-string, T[]> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string, T[]>.
Loading history...
27
     */
28 26
    public function getRecursiveClassAttributes(ReflectionClass $class, string $attributeName): array
29
    {
30 26
        $result = [];
31
32 26
        $attributes = $this->getAttributeInstances($class, $attributeName);
33 26
        if ($attributes) {
34 26
            $result[$class->getName()] = $attributes;
35
        }
36
37 26
        foreach ($class->getTraits() as $trait) {
38 2
            $result = array_merge($result, self::getRecursiveClassAttributes($trait, $attributeName));
0 ignored issues
show
Bug Best Practice introduced by
The method GraphQL\Doctrine\Attribu...ursiveClassAttributes() is not static, but was called statically. ( Ignorable by Annotation )

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

38
            $result = array_merge($result, self::/** @scrutinizer ignore-call */ getRecursiveClassAttributes($trait, $attributeName));
Loading history...
39
        }
40
41 26
        $parent = $class->getParentClass();
42 26
        if ($parent) {
43 24
            $result = array_merge($result, self::getRecursiveClassAttributes($parent, $attributeName));
44
        }
45
46 26
        return $result;
47
    }
48
49
    /**
50
     * @template T of ApiAttribute
51
     *
52
     * @param class-string<T> $attributeName
53
     *
54
     * @return null|T
55
     */
56 40
    public function getAttribute(ReflectionClass|ReflectionProperty|ReflectionMethod|ReflectionParameter $element, string $attributeName): ?ApiAttribute
57
    {
58 40
        $attributes = $this->getAttributeInstances($element, $attributeName);
59
60 40
        return $this->onlyOne($attributes);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->onlyOne($attributes) also could return the type GraphQL\Doctrine\Attribute\ApiAttribute which is incompatible with the documented return type GraphQL\Doctrine\Attribute\Reader\T|null.
Loading history...
61
    }
62
63
    /**
64
     * @template T of ApiAttribute
65
     *
66
     * @param T[] $attributes
67
     *
68
     * @return null|T
1 ignored issue
show
Bug introduced by
The type GraphQL\Doctrine\Attribute\Reader\T was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
69
     */
70 40
    private function onlyOne(array $attributes): ?ApiAttribute
71
    {
72 40
        if (count($attributes) > 1) {
73
            throw new Exception('Expected to find single attribute, but found many');
74
        }
75
76 40
        return reset($attributes) ?: null;
77
    }
78
79
    /**
80
     * @template T of ApiAttribute
81
     *
82
     * @param class-string<T> $attributeName
83
     *
84
     * @return T[]
85
     */
86 49
    private function getAttributeInstances(ReflectionClass|ReflectionMethod|ReflectionParameter|ReflectionProperty $element, string $attributeName): array
87
    {
88 49
        if (!is_subclass_of($attributeName, ApiAttribute::class)) {
89
            throw new Exception('This should not be used for attribute than are not ours');
90
        }
91
92 49
        $attributes = $element->getAttributes($attributeName);
93 49
        $instances = [];
94
95 49
        foreach ($attributes as $attribute) {
96 44
            $instance = $attribute->newInstance();
97
            assert($instance instanceof ApiAttribute);
98
99 44
            $instances[] = $instance;
100
        }
101
102 49
        return $instances;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $instances returns an array which contains values of type GraphQL\Doctrine\Attribute\ApiAttribute which are incompatible with the documented value type GraphQL\Doctrine\Attribute\Reader\T.
Loading history...
103
    }
104
}
105