Test Failed
Push — main ( 2b582c...894963 )
by Rafael
05:38
created

Dispatcher::runApi()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 30
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 21
dl 0
loc 30
rs 9.584
c 0
b 0
f 0
cc 4
nc 8
nop 2
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\Lib;
20
21
use Alxarafe\Base\Controller\ApiController;
22
use Alxarafe\Tools\Debug;
23
use CoreModules\Admin\Controller\Error404Controller;
24
use DebugBar\DebugBarException;
25
26
class Dispatcher
27
{
28
    /**
29
     * Get variable containing the name of the module to which the controller to be executed belongs.
30
     */
31
    public const MODULE = 'module';
32
33
    /**
34
     * Get variable containing the name of the controller to execute.
35
     */
36
    public const CONTROLLER = 'controller';
37
38
    /**
39
     * Get variable containing the name of the method to execute.
40
     * Not normally used. The action is executed automatically from the index method.
41
     */
42
    private const METHOD = 'method';
43
44
    /**
45
     * Run de selected controller.
46
     * Discriminates by URL whether to paint a web page, or return an API response.
47
     *
48
     * @throws DebugBarException
49
     */
50
    public static function run($alternative_routes = []): void
51
    {
52
        self::initialize();
53
54
        $to_search = '/index.php/api/';
55
        $route = $_SERVER['PHP_SELF'];
56
        $pos = strpos($route, $to_search);
57
        if ($pos !== false) {
58
            $controller = substr($route, $pos + strlen($to_search));
59
            static::runApi($controller, $alternative_routes);
60
            return;
61
        }
62
63
        $module = filter_input(INPUT_GET, static::MODULE) ?? 'Admin';
64
        $controller = filter_input(INPUT_GET, static::CONTROLLER) ?? 'Info';
65
        $method = filter_input(INPUT_GET, static::METHOD) ?? 'index';
66
        if (!static::runWeb($module, $controller, $method, $alternative_routes)) {
67
            new Error404Controller();
68
        }
69
    }
70
71
    /**
72
     * Initializes all the utilities and libraries of the framework environment.
73
     *
74
     * @return void
75
     * @throws DebugBarException
76
     */
77
    private static function initialize()
78
    {
79
        self::initializeConstants();
80
81
        Trans::initialize();
82
    }
83
84
    private static function initializeConstants()
85
    {
86
        /**
87
         * Define BASE_PATH if it does not exist.
88
         * It's usually created in main index.php.
89
         * It's the full path to the public folder.
90
         */
91
        Functions::defineIfNotDefined('ALX_PATH', realpath(__DIR__ . '/../../..'));
92
        Functions::defineIfNotDefined('APP_PATH', realpath(constant('ALX_PATH') . '/../../..'));
93
        Functions::defineIfNotDefined('BASE_PATH', constant('APP_PATH') . '/public');
94
        Functions::defineIfNotDefined('BASE_URL', Functions::getUrl());
95
    }
96
97
    private static function runApi($route, $alternative_routes)
98
    {
99
        $array = explode('/', $route);
100
        $module = $array[0];
101
        $controller = $array[1] ?? null;
102
        $method = $array[2] ?? null;
0 ignored issues
show
Unused Code introduced by
The assignment to $method is dead and can be removed.
Loading history...
103
104
        $routes = Routes::getAllRoutes();
105
        $endpoint = $routes['Api'][$module][$controller] ?? null;
106
        if ($endpoint === null) {
107
            Debug::message("Dispatcher::runApi error: $route does not exists");
108
            ApiController::badApiCall();
109
        }
110
111
        Debug::message("Dispatcher::runApi executing $route ($endpoint)");
112
        $route_array = explode('|', $endpoint);
113
        $class_name = $route_array[0];
114
        $filename = $route_array[1];
115
116
        if (!file_exists($filename)) {
117
            Debug::message("Dispatcher::runApi error: $filename does not exists");
118
            ApiController::badApiCall();
119
        }
120
121
        require_once $filename;
122
123
        $controller = new $class_name();
124
        if ($controller === null) {
125
            Debug::message("Dispatcher::runApi error: $class_name not found");
126
            ApiController::badApiCall();
127
        }
128
    }
129
130
    /**
131
     * Run the controller for the indicated module, if it exists.
132
     * Returns true if it can be executed.
133
     *
134
     * @param string $module
135
     * @param string $controller
136
     * @param string $method
137
     * @param array $alternative_routes
138
     *
139
     * @return bool
140
     * @throws DebugBarException
141
     */
142
    private static function runWeb(string $module, string $controller, string $method, array $alternative_routes): bool
143
    {
144
        Debug::initialize();
145
146
        $routes = Routes::getAllRoutes();
147
        $endpoint = $routes['Controller'][$module][$controller] ?? null;
148
        if ($endpoint === null) {
149
            Debug::message("Dispatcher::runWeb error: $module::$controller does not exists");
150
            new Error404Controller();
151
            return false;
152
        }
153
154
        Debug::message("Dispatcher::runWeb executing $module::$controller ($endpoint)");
155
        $route_array = explode('|', $endpoint);
156
        $class_name = $route_array[0];
157
        $filename = $route_array[1];
158
159
        if (!file_exists($filename)) {
160
            Debug::message("Dispatcher::runWeb error: $filename does not exists");
161
            new Error404Controller();
162
            return false;
163
        }
164
165
        require_once $filename;
166
167
        $controller = new $class_name();
168
        if ($controller === null) {
169
            Debug::message("Dispatcher::runApi error: $class_name not found");
170
            new Error404Controller();
171
            return false;
172
        }
173
174
        $templates_path = [
175
            constant('ALX_PATH') . '/src/Modules/' . $module . '/Templates/',
176
            constant('BASE_PATH') . '/../Modules/' . $module . '/Templates/',
177
        ];
178
179
        /**
180
         * If the class exists and is successfully instantiated, the module blade templates folder
181
         * is added, if they exist.
182
         */
183
        if (method_exists($controller, 'setTemplatesPath')) {
184
            Debug::message('Templates: ' . $templates_path[0]);
185
            Debug::message('Templates: ' . $templates_path[1]);
186
            $controller->setTemplatesPath($templates_path);
187
        }
188
189
        if (!method_exists($controller, $method)) {
190
            Debug::message('Method ' . $method . ' not found in controller ' . $class_name);
191
            $method = 'index';
192
        }
193
194
        /**
195
         * Runs the index method to launch the controller.
196
         */
197
        $controller->{$method}();
198
199
        return true;
200
    }
201
202
    /**
203
     * Process modern application controller paths.
204
     *
205
     * @param string $class
206
     * @param string $route
207
     * @param string $module
208
     * @param string $controller
209
     * @param string $method
210
     * @return bool
211
     */
212
    private static function processFolder(string $class, string $route, string $module, string $controller, string $method = 'index'): bool
213
    {
214
        /**
215
         * Defines the full path ($realpath) to the modules folder ($route).
216
         */
217
        $realpath = realpath(constant('APP_PATH') . '/' . $route);
218
219
        /**
220
         * Adds the module to the path ($basepath), if it's a module.
221
         */
222
        $basepath = $realpath;
223
        if (!empty($module)) {
224
            $basepath = $realpath . '/' . $module;
225
        }
226
227
        /**
228
         * Defines full classname and filename
229
         */
230
        $className = $class . '\\' . $module . '\\Controller\\' . $controller;
231
        $filename = $basepath . '/Controller/' . $controller . '.php';
232
233
        Debug::message('Filename: ' . $filename);
234
        Debug::message('Class: ' . $className);
235
        if (!file_exists($filename)) {
236
            return false;
237
        }
238
239
        require_once $filename;
240
241
        $controller = new $className();
242
        if ($controller === null) {
243
            return false;
244
        }
245
246
        /**
247
         * If the class exists and is successfully instantiated, the module blade templates folder
248
         * is added, if they exist.
249
         */
250
        if (method_exists($controller, 'setTemplatesPath')) {
251
            $templates_path = $basepath . '/Templates';
252
            Debug::message('Templates: ' . $templates_path);
253
            $controller->setTemplatesPath($templates_path);
254
        }
255
256
        if (!method_exists($controller, $method)) {
257
            Debug::message('Method ' . $method . ' not found in controller ' . $className);
258
            $method = 'index';
259
        }
260
261
        /**
262
         * Runs the index method to launch the controller.
263
         */
264
        $controller->{$method}();
265
266
        return true;
267
    }
268
}
269