Passed
Push — master ( 629e50...00dea8 )
by Rustam
08:02 queued 07:25
created

Classifier::find()   C

Complexity

Conditions 14
Paths 27

Size

Total Lines 51
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 14.0066

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 14
eloc 29
nc 27
nop 0
dl 0
loc 51
ccs 30
cts 31
cp 0.9677
crap 14.0066
rs 6.2666
c 4
b 0
f 0

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
     * @psalm-param class-string ...$interfaces
32
     */
33 9
    public function withInterface(string ...$interfaces): self
34
    {
35 9
        $new = clone $this;
36 9
        array_push($new->interfaces, ...array_values($interfaces));
37
38 9
        return $new;
39
    }
40
41
    /**
42
     * @psalm-param class-string $parent
43
     */
44 1
    public function withParent(string $parent): self
45
    {
46 1
        $new = clone $this;
47 1
        $new->parent = $parent;
48 1
        return $new;
49
    }
50
51
    /**
52
     * @psalm-param class-string ...$attributes
53
     */
54 4
    public function withAttribute(string ...$attributes): self
55
    {
56 4
        $new = clone $this;
57 4
        array_push($new->attributes, ...array_values($attributes));
58
59 4
        return $new;
60
    }
61
62 12
    public function find(): iterable
63
    {
64 12
        $countInterfaces = count($this->interfaces);
65 12
        $countAttributes = count($this->attributes);
66
67 12
        if ($countInterfaces === 0 && $countAttributes === 0 && $this->parent === null) {
68 3
            return [];
69
        }
70
71 9
        $this->scanFiles();
72
73 9
        $classesToFind = get_declared_classes();
74
75 9
        $baseDirectory = $this->directory;
76 9
        if (DIRECTORY_SEPARATOR === '\\') {
77
            $baseDirectory = str_replace('/', '\\', $baseDirectory);
78
        }
79
80 9
        foreach ($classesToFind as $className) {
81 9
            $reflection = new ReflectionClass($className);
82 9
            $filePath = $reflection->getFileName();
83 9
            if ($filePath === false || !str_starts_with($filePath, $baseDirectory)) {
84 9
                continue;
85
            }
86
87 9
            if ($countInterfaces > 0) {
88 7
                $interfaces = $reflection->getInterfaces();
89 7
                $interfaces = array_map(static fn(ReflectionClass $class) => $class->getName(), $interfaces);
90
91 7
                if (count(array_intersect($this->interfaces, $interfaces)) !== $countInterfaces) {
92 5
                    continue;
93
                }
94
            }
95
96 9
            if ($countAttributes > 0) {
97 2
                $attributes = $reflection->getAttributes();
98 2
                $attributes = array_map(
99 2
                    static fn(ReflectionAttribute $attribute) => $attribute->getName(),
100 2
                    $attributes
101 2
                );
102
103 2
                if (count(array_intersect($this->attributes, $attributes)) !== $countAttributes) {
104 2
                    continue;
105
                }
106
            }
107
108 9
            if (($this->parent !== null) && !is_subclass_of($className, $this->parent)) {
109 1
                continue;
110
            }
111
112 9
            yield $className;
113
        }
114
    }
115
116
    /**
117
     * @psalm-suppress UnresolvableInclude
118
     */
119 9
    private function scanFiles(): void
120
    {
121 9
        $files = (new Finder())
122 9
            ->in($this->directory)
123 9
            ->name('*.php')
124 9
            ->sortByName()
125 9
            ->files();
126
127 9
        foreach ($files as $file) {
128 9
            require_once $file;
129
        }
130
    }
131
}
132