AllAppModulesFinder::createAppModule()   B
last analyzed

Complexity

Conditions 7
Paths 6

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7.0099

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 17
c 1
b 0
f 0
nc 6
nop 2
dl 0
loc 30
ccs 16
cts 17
cp 0.9412
crap 7.0099
rs 8.8333
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Console\Domain\AllAppModules;
6
7
use Gacela\Framework\AbstractFacade;
8
use OuterIterator;
9
use RecursiveDirectoryIterator;
10
use RecursiveIteratorIterator;
11
use ReflectionClass;
12
use SplFileInfo;
13
14 6
use function sprintf;
15
16
final class AllAppModulesFinder
17
{
18 6
    /**
19
     * @param RecursiveIteratorIterator<RecursiveDirectoryIterator> $fileIterator
20
     */
21
    public function __construct(
22
        private readonly OuterIterator $fileIterator,
23 6
        private readonly AppModuleCreator $appModuleCreator,
24
    ) {
25 6
    }
26
27
    /**
28 6
     * @return list<AppModule>
29 6
     */
30 6
    public function findAllAppModules(string $filter): array
31 6
    {
32
        $result = [];
33
34 6
        /** @var SplFileInfo $fileInfo */
35
        foreach ($this->fileIterator as $fileInfo) {
36 6
            $appModule = $this->createAppModule($fileInfo, $filter);
37
            if ($appModule instanceof AppModule && $this->isFacade($appModule)) {
38
                $result[$appModule->facadeClass()] = $appModule;
39 6
            }
40
        }
41 6
42 6
        uksort($result, static fn ($a, $b): int => $a <=> $b);
43 6
44
        return array_values($result);
45 4
    }
46
47
    private function createAppModule(SplFileInfo $fileInfo, string $filter): ?AppModule
48 6
    {
49 6
        if (!$fileInfo->isFile()
50
            || $fileInfo->getExtension() !== 'php'
51 6
            || str_contains($fileInfo->getRealPath(), 'vendor' . DIRECTORY_SEPARATOR)
52 6
        ) {
53 6
            return null;
54 6
        }
55 6
56
        $namespace = $this->getNamespace($fileInfo);
57 6
        $className = $this->buildClassName($fileInfo);
58 3
59 3
        $fullyQualifiedClassName = sprintf(
60 3
            '%s\\%s',
61
            $namespace,
62
            $className,
63
        );
64 6
65
        if ($filter !== '') {
66
            $filterNamespace = str_replace('/', '\\', $filter);
67
            if (!str_contains($fullyQualifiedClassName, $filterNamespace)) {
68 6
                return null;
69
            }
70
        }
71 6
72
        if (!class_exists($fullyQualifiedClassName)) {
73 6
            return null;
74
        }
75 6
76
        return $this->appModuleCreator->fromClass($fullyQualifiedClassName);
77 6
    }
78
79
    private function getNamespace(SplFileInfo $fileInfo): string
80 6
    {
81
        $fileContent = (string)file_get_contents($fileInfo->getRealPath());
82 6
83 6
        preg_match('#namespace (.*);#', $fileContent, $matches);
84
85 6
        return $matches[1] ?? '';
86
    }
87
88 6
    private function buildClassName(SplFileInfo $fileInfo): string
89
    {
90 6
        $pieces = explode(DIRECTORY_SEPARATOR, $fileInfo->getFilename());
91 6
        $filename = end($pieces);
92
93 6
        return substr($filename, 0, strpos($filename, '.') ?: 1);
94 6
    }
95
96
    private function isFacade(AppModule $appModule): bool
97
    {
98
        $rc = new ReflectionClass($appModule->facadeClass());
99
        $parentClass = $rc->getParentClass();
100
101
        return $parentClass !== false
102
            && $parentClass->name === AbstractFacade::class;
103
    }
104
}
105