Passed
Pull Request — master (#1)
by Peter
07:07
created

Loader   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 46
dl 0
loc 121
rs 10
c 2
b 0
f 0
wmc 23

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 2
A loadModules() 0 18 4
A sortModules() 0 24 6
B scanDirectories() 0 21 8
A findModules() 0 13 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AbterPhp\Framework\Module;
6
7
use AbterPhp\Framework\Constant\Module;
8
9
class Loader
10
{
11
    protected const MODULE_FILE_NAME = 'abter.php';
12
13
    protected const ERROR_MSG_UNRESOLVABLE_DEPENDENCIES = 'Not able to determine module order. Likely circular dependency found.'; // phpcs:ignore
14
15
    /** @var string[] */
16
    protected $sourceRoots;
17
18
    /** @var string */
19
    protected $moduleFileName;
20
21
    /**
22
     * Loader constructor.
23
     *
24
     * @param array  $sourceRoots
25
     * @param string $moduleFileName
26
     */
27
    public function __construct(array $sourceRoots, $moduleFileName = '')
28
    {
29
        $this->sourceRoots = $sourceRoots;
30
31
        $this->moduleFileName = $moduleFileName ?: static::MODULE_FILE_NAME;
32
    }
33
34
    /**
35
     * @return array
36
     */
37
    public function loadModules(): array
38
    {
39
        $rawModules = [];
40
        foreach ($this->findModules() as $path) {
41
            $rawModule = include $path;
42
43
            if (empty($rawModule[Module::ENABLED])) {
44
                continue;
45
            }
46
47
            $rawModules[] = $rawModule;
48
        }
49
50
        if (count($rawModules) === 0) {
51
            return [];
52
        }
53
54
        return $this->sortModules($rawModules);
55
    }
56
57
    /**
58
     * @return array
59
     */
60
    protected function sortModules(array $rawModules, array $sortedIds = []): array
61
    {
62
        $sortedModules = [];
63
        while (!empty($rawModules)) {
64
            $sortedCount = count($sortedIds);
65
66
            foreach ($rawModules as $idx => $rawModule) {
67
                foreach ($rawModule[Module::DEPENDENCIES] as $dep) {
68
                    if (!isset($sortedIds[$dep])) {
69
                        continue 2;
70
                    }
71
                }
72
73
                $sortedIds[$rawModule[Module::IDENTIFIER]] = $rawModule[Module::IDENTIFIER];
74
                $sortedModules[] = $rawModule;
75
                unset($rawModules[$idx]);
76
            }
77
78
            if ($sortedCount === count($sortedIds)) {
79
                throw new \LogicException(static::ERROR_MSG_UNRESOLVABLE_DEPENDENCIES);
80
            }
81
        }
82
83
        return $sortedModules;
84
    }
85
86
    /**
87
     * @return array
88
     */
89
    protected function findModules(): array
90
    {
91
        $paths = [];
92
93
        foreach ($this->sourceRoots as $root) {
94
            if (empty($root)) {
95
                continue;
96
            }
97
98
            $paths = array_merge($paths, $this->scanDirectories(new \DirectoryIterator($root)));
99
        }
100
101
        return $paths;
102
    }
103
104
    /**
105
     * @param \DirectoryIterator $directoryIterator
106
     *
107
     * @return array
108
     */
109
    protected function scanDirectories(\DirectoryIterator $directoryIterator): array
110
    {
111
        $paths = [];
112
        foreach ($directoryIterator as $fileInfo) {
113
            if ($fileInfo->isDot() || !$fileInfo->isFile()) {
114
                continue;
115
            }
116
            if ($fileInfo->getFilename() === $this->moduleFileName) {
117
                return [$fileInfo->getRealPath()];
118
            }
119
        }
120
121
        foreach ($directoryIterator as $fileInfo) {
122
            if ($fileInfo->isDot() || !$fileInfo->isDir()) {
123
                continue;
124
            }
125
126
            $paths = array_merge($paths, $this->scanDirectories(new \DirectoryIterator($fileInfo->getRealPath())));
127
        }
128
129
        return $paths;
130
    }
131
}
132