Test Failed
Pull Request — main (#139)
by Daniel
16:46
created

AttributeReader   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 124
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 52
dl 0
loc 124
rs 10
c 0
b 0
f 0
wmc 21

7 Methods

Rating   Name   Duplication   Size   Complexity  
A resolveClassName() 0 16 4
A isConfigured() 0 9 2
A getConfigurationFromTraits() 0 13 3
A getClassAttributeConfiguration() 0 17 3
A getConfigurationFromParentClasses() 0 14 3
A __construct() 0 3 1
A findAttributeConfiguration() 0 16 5
1
<?php
2
3
/*
4
 * This file is part of the Silverback API Components Bundle Project
5
 *
6
 * (c) Daniel West <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Silverback\ApiComponentsBundle\AttributeReader;
15
16
use Doctrine\Persistence\ManagerRegistry;
17
use JetBrains\PhpStorm\Pure;
18
use Silverback\ApiComponentsBundle\Exception\InvalidArgumentException;
19
use Silverback\ApiComponentsBundle\Utility\ClassMetadataTrait;
20
21
/**
22
 * @author Vincent Chalamon <[email protected]>
23
 * @author Daniel West <[email protected]>
24
 */
25
abstract class AttributeReader implements AttributeReaderInterface
26
{
27
    use ClassMetadataTrait;
28
29
    private array $configurationCache = [];
30
31
    public function __construct(ManagerRegistry $managerRegistry)
32
    {
33
        $this->initRegistry($managerRegistry);
34
    }
35
36
    abstract public function getConfiguration(object|string $class);
37
38
    public function isConfigured(object|string $class): bool
39
    {
40
        try {
41
            $this->getConfiguration($class);
42
        } catch (InvalidArgumentException $e) {
43
            return false;
44
        }
45
46
        return true;
47
    }
48
49
    private function resolveClassName(object|string|null $class): string
50
    {
51
        $error = sprintf('$class passed to %s must be a valid class FQN or object.', __CLASS__);
52
        if (null === $class) {
53
            throw new InvalidArgumentException($error . ' It is null.');
54
        }
55
56
        if (\is_string($class)) {
57
            if (!class_exists($class)) {
58
                throw new InvalidArgumentException(sprintf('%s %s is not a class.', $error, $class));
59
            }
60
61
            return $class;
62
        }
63
64
        return \get_class($class);
65
    }
66
67
    /**
68
     * @throws \ReflectionException
69
     */
70
    protected function getClassAttributeConfiguration(object|string|null $class, string $annotationClass): ?object
71
    {
72
        $className = $this->resolveClassName($class);
73
        if (\array_key_exists($className, $this->configurationCache)) {
74
            return $this->configurationCache[$className];
75
        }
76
77
        $attributes = $this->findAttributeConfiguration($class, $annotationClass);
78
        if (!\count($attributes)) {
79
            return null;
80
        }
81
82
        $attribute = $attributes[0];
83
        $instance = $attribute->newInstance();
84
        $this->configurationCache[$className] = $instance;
85
86
        return $instance;
87
    }
88
89
    /**
90
     * @param string|object $class
91
     *
92
     * @throws \ReflectionException
93
     *
94
     * @return \ReflectionAttribute[]
95
     */
96
    private function findAttributeConfiguration($class, string $annotationClass): array
97
    {
98
        $reflection = new \ReflectionClass($class);
99
        $attributes = $reflection->getAttributes($annotationClass);
100
101
        if (!\count($attributes)) {
102
            $attributes = $this->getConfigurationFromParentClasses($reflection, $annotationClass);
103
            if (!\count($attributes)) {
104
                $attributes = $this->getConfigurationFromTraits($reflection, $annotationClass);
105
                if (!\count($attributes)) {
106
                    throw new InvalidArgumentException(sprintf('%s does not have %s annotation', \is_object($class) ? \get_class($class) : $class, $annotationClass));
107
                }
108
            }
109
        }
110
111
        return $attributes;
112
    }
113
114
    /**
115
     * @return \ReflectionAttribute[]
116
     */
117
    #[Pure]
118
    private function getConfigurationFromParentClasses(\ReflectionClass $reflection, string $annotationClass): array
119
    {
120
        $attributes = [];
121
122
        $parentReflection = $reflection->getParentClass();
123
        while (
124
            $parentReflection &&
125
            !$attributes = $parentReflection->getAttributes($annotationClass)
126
        ) {
127
            $parentReflection = $parentReflection->getParentClass();
128
        }
129
130
        return $attributes;
131
    }
132
133
    /**
134
     * @return \ReflectionAttribute[]
135
     */
136
    #[Pure]
137
    private function getConfigurationFromTraits(\ReflectionClass $reflection, string $annotationClass): array
138
    {
139
        $attributes = [];
140
        $traits = $reflection->getTraits();
141
        foreach ($traits as $trait) {
142
            $attributes = $trait->getAttributes($annotationClass);
143
            if (\count($attributes)) {
144
                break;
145
            }
146
        }
147
148
        return $attributes;
149
    }
150
}
151