Passed
Push — master ( 943f18...629e50 )
by Dmitriy
13:05 queued 10:31
created

Classifier::find()   C

Complexity

Conditions 14
Paths 35

Size

Total Lines 53
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 14.0059

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 14
eloc 30
c 4
b 0
f 0
nc 35
nop 0
dl 0
loc 53
ccs 31
cts 32
cp 0.9688
crap 14.0059
rs 6.2666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
        $baseDirectory = $this->directory;
78 9
        if (DIRECTORY_SEPARATOR === '\\') {
79
            $baseDirectory = str_replace('/', '\\', $baseDirectory);
80
        }
81
82 9
        foreach ($classesToFind as $className) {
83 9
            $reflection = new ReflectionClass($className);
84 9
            $filePath = $reflection->getFileName();
85 9
            if ($filePath === false || !str_starts_with($filePath, $baseDirectory)) {
86 9
                continue;
87
            }
88
89 9
            if ($countInterfaces > 0) {
90 7
                $interfaces = $reflection->getInterfaces();
91 7
                $interfaces = array_map(fn(ReflectionClass $class) => $class->getName(), $interfaces);
92
93 7
                if (count(array_intersect($this->interfaces, $interfaces)) !== $countInterfaces) {
94 5
                    continue;
95
                }
96
            }
97
98 9
            if ($countAttributes > 0) {
99 2
                $attributes = $reflection->getAttributes();
100 2
                $attributes = array_map(
101 2
                    static fn(ReflectionAttribute $attribute) => $attribute->getName(),
102 2
                    $attributes
103 2
                );
104
105 2
                if (count(array_intersect($this->attributes, $attributes)) !== $countAttributes) {
106 2
                    continue;
107
                }
108
            }
109
110 9
            if ($this->parent !== null) {
111 1
                if (!is_subclass_of($className, $this->parent)) {
112 1
                    continue;
113
                }
114
            }
115
116 9
            yield $className;
117
        }
118
    }
119
120
    /**
121
     * @psalm-suppress UnresolvableInclude
122
     */
123 9
    private function scanFiles(): void
124
    {
125 9
        $files = (new Finder())
126 9
            ->in($this->directory)
127 9
            ->name('*.php')
128 9
            ->sortByName()
129 9
            ->files();
130
131 9
        foreach ($files as $file) {
132 9
            require_once $file;
133
        }
134
    }
135
}
136