Test Failed
Push — main ( b4a480...c92e2e )
by Rafael
04:40
created

ModuleManager::routes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
dl 0
loc 13
rs 9.9666
c 1
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
/* Copyright (C) 2024      Rafael San José      <[email protected]>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <https:\\www.gnu.org/licenses/>.
17
 */
18
19
namespace Alxarafe\Tools;
20
21
abstract class ModuleManager
22
{
23
    public static function regenerate()
24
    {
25
        dump([
26
            'acciones' => self::getActions(),
27
            'menú refactorizado' => self::buildMultiLevelMenu(self::getMenu()),
28
            'menú lateral' => self::buildMultiLevelMenu(self::getSidebarMenu())
29
        ]);
30
    }
31
32
    /**
33
     * Returns an associative array with the actions of each controller,
34
     * the index being the namespace of the controller.
35
     *
36
     * @return array
37
     */
38
    private static function getActions()
39
    {
40
        $result = [];
41
        $menuOptions = self::iterateFunction('getActions');
42
        foreach ($menuOptions as $option) {
43
            if ($option === false) {
44
                continue;
45
            }
46
            $result = array_merge($result, $option);
47
        }
48
        return $result;
49
    }
50
51
    /**
52
     * Generates an array in which each element is the result of calling the
53
     * $function function for each controller in the application.
54
     *
55
     * @param $function
56
     * @return array
57
     */
58
    private static function iterateFunction($function)
59
    {
60
        $iterate = static::iterate();
61
        $result = [];
62
        foreach ($iterate as $module) {
63
            $namespace = $module['namespace'];
64
            if (!method_exists($namespace, $function)) {
65
                continue;
66
            }
67
            $result[$namespace] = $namespace::$function();
68
        }
69
        return $result;
70
    }
71
72
    private static function iterate()
73
    {
74
        $routes = self::routes();
75
        $data = [];
76
        foreach ($routes as $route) {
77
            $data = array_merge($data, self::getModuleControllers($route['namespace'], $route['path']));
78
        }
79
        return $data;
80
    }
81
82
    /**
83
     * Returns the paths that can contain modules.
84
     *
85
     * @return string[]
86
     */
87
    private static function routes(): array
88
    {
89
        $base_path = realpath(constant('BASE_PATH') . '/..');
90
        $result = [];
91
        $result[] = [
92
            'path' => $base_path . '/vendor/rsanjoseo/alxarafe/src/Modules',
93
            'namespace' => 'CoreModules',
94
        ];
95
        $result[] = [
96
            'path' => $base_path . '/Modules',
97
            'namespace' => 'Modules',
98
        ];
99
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result returns the type array<mixed,array<string,string>> which is incompatible with the documented return type string[].
Loading history...
100
    }
101
102
    /**
103
     * Returns an array with the module drivers included in the $path folder.
104
     * The array contains the name, namespace and path of those controllers.
105
     *
106
     * @param string $namespace
107
     * @param string $path
108
     * @return array
109
     */
110
    private static function getModuleControllers(string $namespace, string $path): array
111
    {
112
        $result = [];
113
        $directories = scandir($path);
114
        foreach ($directories as $directory) {
115
            if ($directory === '.' || $directory === '..' || !is_dir($path . '/' . $directory)) {
116
                continue;
117
            }
118
            $result = array_merge($result, self::getControllers($namespace . '\\' . $directory, $path, $directory));
119
        }
120
        return $result;
121
    }
122
123
    /**
124
     * Returns an array with the specified $path and $directory controllers.
125
     * The array contains the name, namespace and path of those controllers.
126
     *
127
     * @param string $namespace
128
     * @param string $path
129
     * @param string $directory
130
     * @return array
131
     */
132
    private static function getControllers(string $namespace, string $path, string $directory): array
133
    {
134
        $result = [];
135
        $files = scandir($path . '/' . $directory . '/Controller');
136
        foreach ($files as $file) {
137
            if ($file === '.' || $file === '..' || !str_ends_with($file, '.php')) {
138
                continue;
139
            }
140
            $name = substr($file, 0, -4);
141
            $result[] = [
142
                'name' => $name,
143
                'namespace' => $namespace . '\\Controller\\' . $name,
144
                'path' => $path . '/' . $directory . '/Controller/' . $file,
145
            ];
146
        }
147
        return $result;
148
    }
149
150
    /**
151
     * Converts an array where the index is a menu path with the
152
     * hierarchy separated by pipelines, to a nested array.
153
     *
154
     * @param $menuOptions
155
     * @return array|mixed
156
     */
157
    private static function buildMultiLevelMenu($menuOptions)
158
    {
159
        $result = [];
160
161
        foreach ($menuOptions as $option => $value) {
162
            $levels = explode('|', $option);
163
            $numberOfLevels = count($levels);
164
            $currentLevel = &$result;
165
166
            foreach ($levels as $level) {
167
                $numberOfLevels--;
168
                if ($numberOfLevels === 0) {
169
                    $currentLevel[$level] = $value;
170
                    continue;
171
                }
172
                if (!isset($currentLevel[$level])) {
173
                    $currentLevel[$level] = [];
174
                }
175
                $currentLevel = &$currentLevel[$level];
176
            }
177
        }
178
179
        return $result;
180
    }
181
182
    /**
183
     * Obtains an array with all the menu options where the index is the
184
     * option and the value is the url of the controller to be executed.
185
     *
186
     * Example: ['admin|auth'] = "index.php?module=Admin&controller=Auth"
187
     *
188
     * @return array
189
     */
190
    private static function getMenu()
191
    {
192
        $result = [];
193
        $menuOptions = self::iterateFunction('getMenu');
194
        foreach ($menuOptions as $namespace => $option) {
195
            if ($option === false) {
196
                continue;
197
            }
198
            $url = self::getUrl($namespace);
199
            if ($url === false) {
200
                continue;
201
            }
202
            $result[$option] = $url;
203
        }
204
        return $result;
205
    }
206
207
    /**
208
     * Returns the URL that runs the controller with the given namespace.
209
     *
210
     * The namespace can be:
211
     * - CoreModules\\<module>\\Controller\\<controller>Controller
212
     * - Modules\\<module>\\Controller\\<controller>Controller
213
     *
214
     * @param $namespace
215
     * @return false|string
216
     */
217
    public static function getUrl($namespace)
218
    {
219
        $explode = explode('\\', $namespace);
220
        if (count($explode) < 4) {
221
            return false;
222
        }
223
        $name = $explode[3];
224
        if (!str_ends_with($name, 'Controller')) {
225
            return false;
226
        }
227
        $controller = substr($name, 0, -10);
228
        $module = $explode[1];
229
230
        return 'index.php?module=' . $module . '&controller=' . $controller;
231
    }
232
233
    private static function getSidebarMenu()
234
    {
235
        $result = [];
236
        $menuOptions = self::iterateFunction('getSidebarMenu');
237
        foreach ($menuOptions as $namespace => $option) {
238
            if ($option === false) {
239
                continue;
240
            }
241
            $url = self::getUrl($namespace);
242
            if ($url === false) {
243
                continue;
244
            }
245
            foreach ($option['options'] as $value) {
246
                $result[$option['base']][$value['option']] = $url;
247
            }
248
        }
249
        return $result;
250
    }
251
252
}
253