Passed
Push — master ( 4cd67c...cad0fc )
by Dmitriy
01:02 queued 13s
created

Classifier::withParent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 1
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 10
    public function __construct(private string $directory)
27
    {
28 10
    }
29
30 7
    public function withInterface(string|array $interfaces): self
31
    {
32 7
        $new = clone $this;
33 7
        foreach ((array)$interfaces as $interface) {
34 5
            $new->interfaces[] = $interface;
35
        }
36 7
        return $new;
37
    }
38
39
    /**
40
     * @param class-string $parent
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
41
     */
42 1
    public function withParent(string $parent): self
43
    {
44 1
        $new = clone $this;
45 1
        $new->parent = $parent;
46 1
        return $new;
47
    }
48
49 4
    public function withAttribute(string|array $attributes): self
50
    {
51 4
        $new = clone $this;
52 4
        foreach ((array)$attributes as $attribute) {
53 2
            $new->attributes[] = $attribute;
54
        }
55 4
        return $new;
56
    }
57
58 10
    public function find(): iterable
59
    {
60 10
        $countInterfaces = count($this->interfaces);
61 10
        $countAttributes = count($this->attributes);
62
63 10
        if ($countInterfaces === 0 && $countAttributes === 0 && $this->parent === null) {
64 3
            return [];
65
        }
66
67 7
        $this->scanFiles();
68
69 7
        $classesToFind = get_declared_classes();
70
71 7
        foreach ($classesToFind as $className) {
72 7
            $reflection = new ReflectionClass($className);
73
74 7
            if ($countInterfaces > 0) {
75 5
                $interfaces = $reflection->getInterfaces();
76 5
                $interfaces = array_map(fn (ReflectionClass $class) => $class->getName(), $interfaces);
77
78 5
                if (count(array_intersect($this->interfaces, $interfaces)) !== $countInterfaces) {
79 5
                    continue;
80
                }
81
            }
82
83 7
            if ($countAttributes > 0) {
84 2
                $attributes = $reflection->getAttributes();
85 2
                $attributes = array_map(fn (ReflectionAttribute $attribute) => $attribute->getName(), $attributes);
86
87 2
                if (count(array_intersect($this->attributes, $attributes)) !== $countAttributes) {
88 2
                    continue;
89
                }
90
            }
91
92 7
            if ($this->parent !== null) {
93 1
                if (!is_subclass_of($className, $this->parent)) {
94 1
                    continue;
95
                }
96
            }
97
98 7
            yield $className;
99
        }
100
    }
101
102
    /**
103
     * @psalm-suppress UnresolvableInclude
104
     */
105 7
    private function scanFiles(): void
106
    {
107 7
        $files = (new Finder())
108 7
            ->in($this->directory)
109 7
            ->name('*.php')
110 7
            ->sortByName()
111 7
            ->files();
112
113 7
        foreach ($files as $file) {
114 7
            require_once $file;
115
        }
116
    }
117
}
118