Issues (4)

src/Attributes.php (3 issues)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace RustamWin\Attributes;
6
7
use ReflectionClass;
8
use ReflectionException;
9
use RustamWin\Attributes\Dto\ResolvedAttribute;
10
use RustamWin\Attributes\Handler\AttributeHandlerInterface;
11
use RustamWin\Attributes\Instantiator\Instantiator;
12
use Spiral\Attributes\AttributeReader;
13
use Spiral\Attributes\ReaderInterface;
14
use Spiral\Tokenizer\ClassLocator;
15
use Symfony\Component\Finder\Finder;
16
17
final class Attributes
18
{
19
    private ReaderInterface $attributeReader;
20
    private AttributeHandlerInterface $attributeHandler;
21
    /**
22
     * @var array<array-key, string>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, string> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, string>.
Loading history...
23
     */
24
    private array $directories = [];
25
    /**
26
     * @var array<class-string>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string>.
Loading history...
27
     */
28
    private array $classes = [];
29
30 1
    public function __construct(
31
        AttributeHandlerInterface $attributeHandler,
32
        ?ReaderInterface $attributeReader = null
33
    ) {
34 1
        $this->attributeHandler = $attributeHandler;
35 1
        $this->attributeReader = $attributeReader ?? new AttributeReader(new Instantiator());
36
    }
37
38
    /**
39
     * @throws ReflectionException
40
     */
41 1
    public function handle(): void
42
    {
43
        /** @var ReflectionClass[] $classes */
44 1
        $classes = array_unique(array_merge($this->getClasses(), $this->loadClasses()));
45 1
        foreach ($classes as $reflectionClass) {
46 1
            $resolvedAttributes = $this->resolveAttributes($reflectionClass);
47 1
            $this->attributeHandler->handle($reflectionClass, $resolvedAttributes);
48
        }
49
    }
50
51
    /**
52
     * @psalm-param array<class-string> $classes
53
     *
54
     * @return $this
55
     */
56 1
    public function setClasses(array $classes): self
57
    {
58 1
        $this->classes = $classes;
59
60 1
        return $this;
61
    }
62
63
    /**
64
     * @param array<array-key, string> $directories
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<array-key, string> at position 2 could not be parsed: Unknown type name 'array-key' at position 2 in array<array-key, string>.
Loading history...
65
     *
66
     * @return $this
67
     */
68 1
    public function setDirectories(array $directories): self
69
    {
70 1
        $this->directories = $directories;
71
72 1
        return $this;
73
    }
74
75 1
    private function resolveAttributes(ReflectionClass $ref): iterable
76
    {
77
        // class attributes
78 1
        foreach ($this->attributeReader->getClassMetadata($ref) as $attribute) {
79 1
            yield new ResolvedAttribute(attribute: $attribute, reflectionTarget: $ref);
80
        }
81
82
        // properties
83 1
        foreach ($ref->getProperties() as $property) {
84 1
            foreach ($this->attributeReader->getPropertyMetadata($property) as $attribute) {
85 1
                yield new ResolvedAttribute(attribute: $attribute, reflectionTarget: $property);
86
            }
87
        }
88
89
        // constants
90 1
        foreach ($ref->getReflectionConstants() as $constant) {
91 1
            foreach ($this->attributeReader->getConstantMetadata($constant) as $attribute) {
92 1
                yield new ResolvedAttribute(attribute: $attribute, reflectionTarget: $constant);
93
            }
94
        }
95
96
        // methods
97 1
        foreach ($ref->getMethods() as $method) {
98 1
            foreach ($this->attributeReader->getFunctionMetadata($method) as $attribute) {
99 1
                yield new ResolvedAttribute(attribute: $attribute, reflectionTarget: $method);
100
                // parameters
101 1
                foreach ($method->getParameters() as $parameter) {
102 1
                    foreach ($this->attributeReader->getParameterMetadata($parameter) as $parameterAttribute) {
103 1
                        yield new ResolvedAttribute(attribute: $parameterAttribute, reflectionTarget: $parameter);
104
                    }
105
                }
106
            }
107
        }
108
    }
109
110
    /**
111
     * @throws ReflectionException
112
     *
113
     * @psalm-return array<array-key, ReflectionClass<object>>
114
     */
115 1
    private function getClasses(): array
116
    {
117 1
        return array_map(
118 1
            static fn (string $className) => new ReflectionClass($className),
119 1
            $this->classes
120
        );
121
    }
122
123
    /**
124
     * @return ReflectionClass[]
125
     *
126
     * @psalm-return list<ReflectionClass<object>>
127
     */
128 1
    private function loadClasses(): array
129
    {
130 1
        if ($this->directories === []) {
131
            return [];
132
        }
133 1
        $finder = Finder::create()->name('*.php')->in($this->directories);
134 1
        $classes = (new ClassLocator($finder))->getClasses();
135
136 1
        return array_values($classes);
137
    }
138
}
139