Passed
Pull Request — master (#21)
by Dmitriy
06:08 queued 03:50
created

Classifier::scanFiles()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 0
dl 0
loc 10
ccs 8
cts 8
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Classifier;
6
7
use ReflectionAttribute;
8
use ReflectionClass;
9
use Symfony\Component\Finder\Finder;
10
11
final class Classifier
12
{
13
    /**
14
     * @var string[]
15
     */
16
    private array $interfaces = [];
17
    /**
18
     * @var string[]
19
     */
20
    private array $attributes = [];
21
    /**
22
     * @psalm-var class-string
23
     */
24
    private ?string $parent = null;
25
26 12
    public function __construct(private string $directory)
27
    {
28 12
    }
29
30
    /**
31
     * @param string|string[] $interfaces
32
     */
33 9
    public function withInterface(string|array $interfaces): self
34
    {
35 9
        $new = clone $this;
36 9
        foreach ((array) $interfaces as $interface) {
37 7
            $new->interfaces[] = $interface;
38
        }
39 9
        return $new;
40
    }
41
42
    /**
43
     * @psalm-param class-string $parent
44
     */
45 1
    public function withParent(string $parent): self
46
    {
47 1
        $new = clone $this;
48 1
        $new->parent = $parent;
49 1
        return $new;
50
    }
51
52
    /**
53
     * @param string|string[] $attributes
54
     */
55 4
    public function withAttribute(string|array $attributes): self
56
    {
57 4
        $new = clone $this;
58 4
        foreach ((array) $attributes as $attribute) {
59 2
            $new->attributes[] = $attribute;
60
        }
61 4
        return $new;
62
    }
63
64 12
    public function find(): iterable
65
    {
66 12
        $countInterfaces = count($this->interfaces);
67 12
        $countAttributes = count($this->attributes);
68
69 12
        if ($countInterfaces === 0 && $countAttributes === 0 && $this->parent === null) {
70 3
            return [];
71
        }
72
73 9
        $this->scanFiles();
74
75 9
        $classesToFind = get_declared_classes();
76
77 9
        foreach ($classesToFind as $className) {
78 9
            $reflection = new ReflectionClass($className);
79 9
            $filePath = $reflection->getFileName();
80 9
            if ($filePath === false || !str_starts_with($filePath, $this->directory)) {
81 9
                continue;
82
            }
83
84 9
            if ($countInterfaces > 0) {
85 7
                $interfaces = $reflection->getInterfaces();
86 7
                $interfaces = array_map(fn(ReflectionClass $class) => $class->getName(), $interfaces);
87
88 7
                if (count(array_intersect($this->interfaces, $interfaces)) !== $countInterfaces) {
89 5
                    continue;
90
                }
91
            }
92
93 9
            if ($countAttributes > 0) {
94 2
                $attributes = $reflection->getAttributes();
95 2
                $attributes = array_map(
96 2
                    static fn(ReflectionAttribute $attribute) => $attribute->getName(),
97 2
                    $attributes
98 2
                );
99
100 2
                if (count(array_intersect($this->attributes, $attributes)) !== $countAttributes) {
101 2
                    continue;
102
                }
103
            }
104
105 9
            if ($this->parent !== null) {
106 1
                if (!is_subclass_of($className, $this->parent)) {
107 1
                    continue;
108
                }
109
            }
110
111 9
            yield $className;
112
        }
113
    }
114
115
    /**
116
     * @psalm-suppress UnresolvableInclude
117
     */
118 9
    private function scanFiles(): void
119
    {
120 9
        $files = (new Finder())
121 9
            ->in($this->directory)
122 9
            ->name('*.php')
123 9
            ->sortByName()
124 9
            ->files();
125
126 9
        foreach ($files as $file) {
127 9
            require_once $file;
128
        }
129
    }
130
}
131