Passed
Push — master ( e3c67b...98eade )
by Fran
08:10
created

Router::executeCachedRoute()   B

Complexity

Conditions 7
Paths 9

Size

Total Lines 26
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 8.8142

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 20
c 1
b 0
f 0
nc 9
nop 4
dl 0
loc 26
ccs 14
cts 21
cp 0.6667
crap 8.8142
rs 8.6666
1
<?php
2
namespace PSFS\base;
3
4
use PSFS\base\config\Config;
5
use PSFS\base\dto\JsonResponse;
6
use PSFS\base\exception\AccessDeniedException;
7
use PSFS\base\exception\AdminCredentialsException;
8
use PSFS\base\exception\ConfigException;
9
use PSFS\base\exception\RouterException;
10
use PSFS\base\types\helpers\GeneratorHelper;
11
use PSFS\base\types\helpers\I18nHelper;
12
use PSFS\base\types\helpers\Inspector;
13
use PSFS\base\types\helpers\RouterHelper;
14
use PSFS\base\types\helpers\SecurityHelper;
15
use PSFS\base\types\traits\SingletonTrait;
16
use PSFS\controller\base\Admin;
17
use PSFS\services\AdminServices;
18
use Symfony\Component\Finder\Finder;
19
use Symfony\Component\Finder\SplFileInfo;
20
21
/**
22
 * Class Router
23
 * @package PSFS
24
 */
25
class Router
26
{
27
    use SingletonTrait;
28
29
    /**
30
     * @var array
31
     */
32
    protected $routing = [];
33
    /**
34
     * @var array
35
     */
36
    protected $slugs = [];
37
    /**
38
     * @var array
39
     */
40
    private $domains = [];
41
    /**
42
     * @var Finder $finder
43
     */
44
    private $finder;
45
    /**
46
     * @var \PSFS\base\Cache $cache
47
     */
48
    private $cache;
49
    /**
50
     * @var bool headersSent
51
     */
52
    protected $headersSent = false;
53
    /**
54
     * @var int
55
     */
56
    protected $cacheType = Cache::JSON;
57
58
    /**
59
     * Router constructor.
60
     * @throws exception\GeneratorException
61
     * @throws ConfigException
62
     * @throws \InvalidArgumentException
63
     */
64 1
    public function __construct()
65
    {
66 1
        $this->finder = new Finder();
67 1
        $this->cache = Cache::getInstance();
68 1
        $this->init();
69 1
    }
70
71
    /**
72
     * @throws exception\GeneratorException
73
     * @throws ConfigException
74
     * @throws \InvalidArgumentException
75
     */
76 1
    public function init()
77
    {
78 1
        list($this->routing, $this->slugs) = $this->cache->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . 'urls.json', $this->cacheType, TRUE);
79 1
        if (empty($this->routing) || Config::getParam('debug', true)) {
80 1
            $this->debugLoad();
81
        } else {
82
            $this->domains = $this->cache->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . 'domains.json', $this->cacheType, TRUE);
83
        }
84 1
        $this->checkExternalModules(false);
85 1
        $this->setLoaded();
86 1
    }
87
88
    /**
89
     * @throws exception\GeneratorException
90
     * @throws ConfigException
91
     * @throws \InvalidArgumentException
92
     */
93 1
    private function debugLoad() {
94 1
        Logger::log('Begin routes load');
95 1
        $this->hydrateRouting();
96 1
        $this->simpatize();
97 1
        Logger::log('End routes load');
98 1
    }
99
100
    /**
101
     * @param \Exception|NULL $exception
102
     * @param bool $isJson
103
     * @return string
104
     * @throws RouterException
105
     */
106
    public function httpNotFound(\Exception $exception = NULL, $isJson = false)
107
    {
108
        Inspector::stats('[Router] Throw not found exception');
109
        if (NULL === $exception) {
110
            Logger::log('Not found page thrown without previous exception', LOG_WARNING);
111
            $exception = new \Exception(t('Page not found'), 404);
112
        }
113
        $template = Template::getInstance()->setStatus($exception->getCode());
114
        if ($isJson || false !== stripos(Request::getInstance()->getServer('CONTENT_TYPE'), 'json')) {
115
            $response = new JsonResponse(null, false, 0, 0, $exception->getMessage());
116
            return $template->output(json_encode($response), 'application/json');
117
        }
118
119
        $notFoundRoute = Config::getParam('route.404');
120
        if(null !== $notFoundRoute) {
121
            Request::getInstance()->redirect($this->getRoute($notFoundRoute, true));
122
        } else {
123
            return $template->render('error.html.twig', array(
124
                'exception' => $exception,
125
                'trace' => $exception->getTraceAsString(),
126
                'error_page' => TRUE,
127
            ));
128
        }
129
    }
130
131
    /**
132
     * @return array
133
     */
134 1
    public function getSlugs()
135
    {
136 1
        return $this->slugs;
137
    }
138
139
    /**
140
     * @return array
141
     */
142 2
    public function getRoutes() {
143 2
        return $this->routing;
144
    }
145
146
    /**
147
     * Method that extract all routes in the platform
148
     * @return array
149
     */
150 1
    public function getAllRoutes()
151
    {
152 1
        $routes = [];
153 1
        foreach ($this->getRoutes() as $path => $route) {
154 1
            if (array_key_exists('slug', $route)) {
155 1
                $routes[$route['slug']] = $path;
156
            }
157
        }
158 1
        return $routes;
159
    }
160
161
    /**
162
     * @param string|null $route
163
     *
164
     * @throws \Exception
165
     * @return string HTML
166
     */
167 2
    public function execute($route)
168
    {
169 2
        Inspector::stats('[Router] Executing the request');
170
        try {
171
            //Search action and execute
172 2
            return $this->searchAction($route);
173 1
        } catch (AccessDeniedException $e) {
174
            Logger::log(t('Solicitamos credenciales de acceso a zona restringida'), LOG_WARNING, ['file' => $e->getFile() . '[' . $e->getLine() . ']']);
175
            return Admin::staticAdminLogon($route);
176 1
        } catch (RouterException $r) {
177 1
            Logger::log($r->getMessage(), LOG_WARNING);
178
        } catch (\Exception $e) {
179
            Logger::log($e->getMessage(), LOG_ERR);
180
            throw $e;
181
        }
182
183 1
        throw new RouterException(t('Página no encontrada'), 404);
0 ignored issues
show
Bug introduced by
It seems like t('Página no encontrada') can also be of type string; however, parameter $message of PSFS\base\exception\RouterException::__construct() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

183
        throw new RouterException(/** @scrutinizer ignore-type */ t('Página no encontrada'), 404);
Loading history...
184
    }
185
186
    /**
187
     * @param string $route
188
     * @return mixed
189
     * @throws AccessDeniedException
190
     * @throws AdminCredentialsException
191
     * @throws RouterException
192
     * @throws \Exception
193
     */
194 2
    protected function searchAction($route)
195
    {
196 2
        Inspector::stats('[Router] Searching action to execute: ' . $route);
197
        //Revisamos si tenemos la ruta registrada
198 2
        $parts = parse_url($route);
199 2
        $path = array_key_exists('path', $parts) ? $parts['path'] : $route;
200 2
        $httpRequest = Request::getInstance()->getMethod();
201 2
        foreach ($this->routing as $pattern => $action) {
202 2
            list($httpMethod, $routePattern) = RouterHelper::extractHttpRoute($pattern);
203 2
            $matched = RouterHelper::matchRoutePattern($routePattern, $path);
204 2
            if ($matched && ($httpMethod === 'ALL' || $httpRequest === $httpMethod) && RouterHelper::compareSlashes($routePattern, $path)) {
205
                // Checks restricted access
206 1
                SecurityHelper::checkRestrictedAccess($route);
207 1
                $get = RouterHelper::extractComponents($route, $routePattern);
208
                /** @var $class \PSFS\base\types\Controller */
209 1
                $class = RouterHelper::getClassToCall($action);
210
                try {
211 1
                    if($this->checkRequirements($action, $get)) {
212 1
                        return $this->executeCachedRoute($route, $action, $class, $get);
0 ignored issues
show
Bug introduced by
$class of type PSFS\base\types\Controller is incompatible with the type string expected by parameter $class of PSFS\base\Router::executeCachedRoute(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

212
                        return $this->executeCachedRoute($route, $action, /** @scrutinizer ignore-type */ $class, $get);
Loading history...
213
                    } else {
214
                        throw new RouterException(t('La ruta no es válida'), 400);
0 ignored issues
show
Bug introduced by
It seems like t('La ruta no es válida') can also be of type string; however, parameter $message of PSFS\base\exception\RouterException::__construct() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

214
                        throw new RouterException(/** @scrutinizer ignore-type */ t('La ruta no es válida'), 400);
Loading history...
215
                    }
216
                } catch (\Exception $e) {
217
                    Logger::log($e->getMessage(), LOG_ERR);
218 2
                    throw $e;
219
                }
220
            }
221
        }
222 1
        throw new RouterException(t('Ruta no encontrada'));
223
    }
224
225
    /**
226
     * @param array $action
227
     * @param array $params
228
     * @return bool
229
     */
230 1
    private function checkRequirements(array $action, $params = []) {
231 1
        Inspector::stats('[Router] Checking request requirements');
232 1
        if(!empty($params) && !empty($action['requirements'])) {
233
            $checked = 0;
234
            foreach(array_keys($params) as $key) {
235
                if(in_array($key, $action['requirements'], true)) {
236
                    $checked++;
237
                }
238
            }
239
            $valid = count($action['requirements']) === $checked;
240
        } else {
241 1
            $valid = true;
242
        }
243 1
        return $valid;
244
    }
245
246
    /**
247
     * @return string HTML
248
     */
249
    protected function sentAuthHeader()
250
    {
251
        return AdminServices::getInstance()->setAdminHeaders();
252
    }
253
254
    /**
255
     * @return string|null
256
     */
257 1
    private function getExternalModules() {
258 1
        $externalModules = Config::getParam('modules.extend', '');
259 1
        $externalModules .= ',psfs/auth,psfs/nosql';
260 1
        return $externalModules;
261
    }
262
263
    /**
264
     * @param boolean $hydrateRoute
265
     */
266 1
    private function checkExternalModules($hydrateRoute = true)
267
    {
268 1
        $externalModules = $this->getExternalModules();
269 1
        if ('' !== $externalModules) {
270 1
            $externalModules = explode(',', $externalModules);
271 1
            foreach ($externalModules as &$module) {
272 1
                $module = $this->loadExternalModule($hydrateRoute, $module);
273
            }
274
        }
275 1
    }
276
277
    /**
278
     * @throws exception\GeneratorException
279
     * @throws ConfigException
280
     * @throws \InvalidArgumentException
281
     */
282 1
    private function generateRouting()
283
    {
284 1
        $base = SOURCE_DIR;
285 1
        $modulesPath = realpath(CORE_DIR);
286 1
        $this->routing = $this->inspectDir($base, 'PSFS', array());
287 1
        $this->checkExternalModules();
288 1
        if (file_exists($modulesPath)) {
289
            $modules = $this->finder->directories()->in($modulesPath)->depth(0);
290
            if($modules->hasResults()) {
291
                foreach ($modules->getIterator() as $modulePath) {
292
                    $module = $modulePath->getBasename();
293
                    $this->routing = $this->inspectDir($modulesPath . DIRECTORY_SEPARATOR . $module, $module, $this->routing);
294
                }
295
            }
296
        }
297 1
        $this->cache->storeData(CONFIG_DIR . DIRECTORY_SEPARATOR . 'domains.json', $this->domains, Cache::JSON, TRUE);
298 1
    }
299
300
    /**
301
     * @throws exception\GeneratorException
302
     * @throws ConfigException
303
     * @throws \InvalidArgumentException
304
     */
305 1
    public function hydrateRouting()
306
    {
307 1
        $this->generateRouting();
308 1
        $home = Config::getParam('home.action');
309 1
        if (NULL !== $home || $home !== '') {
310 1
            $home_params = NULL;
311 1
            foreach ($this->routing as $pattern => $params) {
312 1
                list($method, $route) = RouterHelper::extractHttpRoute($pattern);
313 1
                if (preg_match('/' . preg_quote($route, '/') . '$/i', '/' . $home)) {
314
                    $home_params = $params;
315
                }
316 1
                unset($method);
317
            }
318 1
            if (NULL !== $home_params) {
319
                $this->routing['/'] = $home_params;
320
            }
321
        }
322 1
    }
323
324
    /**
325
     * @param string $origen
326
     * @param string $namespace
327
     * @param array $routing
328
     * @return array
329
     * @throws ConfigException
330
     * @throws \InvalidArgumentException
331
     */
332 1
    private function inspectDir($origen, $namespace = 'PSFS', $routing = [])
333
    {
334 1
        $files = $this->finder->files()->in($origen)->path('/(controller|api)/i')->depth(1)->name('*.php');
335 1
        if($files->hasResults()) {
336 1
            foreach ($files->getIterator() as $file) {
337 1
                if($namespace !== 'PSFS' && method_exists($file, 'getRelativePathname')) {
338
                    $filename = '\\' . str_replace('/', '\\', str_replace($origen, '', $file->getRelativePathname()));
339
                } else {
340 1
                    $filename = str_replace('/', '\\', str_replace($origen, '', $file->getPathname()));
341
                }
342 1
                $routing = $this->addRouting($namespace . str_replace('.php', '', $filename), $routing, $namespace);
343
            }
344
        }
345 1
        $this->finder = new Finder();
346
347 1
        return $routing;
348
    }
349
350
    /**
351
     * @param string $namespace
352
     * @return bool
353
     */
354 3
    public static function exists($namespace)
355
    {
356 3
        return (class_exists($namespace) || interface_exists($namespace) || trait_exists($namespace));
357
    }
358
359
    /**
360
     *
361
     * @param string $namespace
362
     * @param array $routing
363
     * @param string $module
364
     *
365
     * @return array
366
     * @throws ConfigException
367
     */
368 1
    private function addRouting($namespace, &$routing, $module = 'PSFS')
369
    {
370 1
        if (self::exists($namespace)) {
371 1
            if(I18nHelper::checkI18Class($namespace)) {
372
                return $routing;
373
            }
374 1
            $reflection = new \ReflectionClass($namespace);
375 1
            if (false === $reflection->isAbstract() && FALSE === $reflection->isInterface()) {
376 1
                $this->extractDomain($reflection);
377 1
                $classComments = $reflection->getDocComment();
378 1
                preg_match('/@api\ (.*)\n/im', $classComments, $apiPath);
379 1
                $api = '';
380 1
                if (count($apiPath)) {
381
                    $api = array_key_exists(1, $apiPath) ? $apiPath[1] : $api;
382
                }
383 1
                foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
384 1
                    if (preg_match('/@route\ /i', $method->getDocComment())) {
385 1
                        list($route, $info) = RouterHelper::extractRouteInfo($method, str_replace('\\', '', $api), str_replace('\\', '', $module));
386
387 1
                        if (null !== $route && null !== $info) {
388 1
                            $info['class'] = $namespace;
389 1
                            $routing[$route] = $info;
390
                        }
391
                    }
392
                }
393
            }
394
        }
395
396 1
        return $routing;
397
    }
398
399
    /**
400
     *
401
     * @param \ReflectionClass $class
402
     *
403
     * @return Router
404
     * @throws ConfigException
405
     */
406 1
    protected function extractDomain(\ReflectionClass $class)
407
    {
408
        //Calculamos los dominios para las plantillas
409 1
        if ($class->hasConstant('DOMAIN') && !$class->isAbstract()) {
410 1
            if (!$this->domains) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->domains of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
411 1
                $this->domains = [];
412
            }
413 1
            $domain = '@' . $class->getConstant('DOMAIN') . '/';
414 1
            if (!array_key_exists($domain, $this->domains)) {
415 1
                $this->domains[$domain] = RouterHelper::extractDomainInfo($class, $domain);
416
            }
417
        }
418
419 1
        return $this;
420
    }
421
422
    /**
423
     * @return $this
424
     * @throws exception\GeneratorException
425
     * @throws ConfigException
426
     */
427 1
    public function simpatize()
428
    {
429 1
        $translationFileName = 'translations' . DIRECTORY_SEPARATOR . 'routes_translations.php';
430 1
        $absoluteTranslationFileName = CACHE_DIR . DIRECTORY_SEPARATOR . $translationFileName;
431 1
        $this->generateSlugs($absoluteTranslationFileName);
432 1
        GeneratorHelper::createDir(CONFIG_DIR);
433 1
        Cache::getInstance()->storeData(CONFIG_DIR . DIRECTORY_SEPARATOR . 'urls.json', array($this->routing, $this->slugs), Cache::JSON, TRUE);
434
435 1
        return $this;
436
    }
437
438
    /**
439
     * @param string $slug
440
     * @param boolean $absolute
441
     * @param array $params
442
     *
443
     * @return string|null
444
     * @throws RouterException
445
     */
446 3
    public function getRoute($slug = '', $absolute = FALSE, array $params = [])
447
    {
448 3
        if ('' === $slug) {
449 1
            return $absolute ? Request::getInstance()->getRootUrl() . '/' : '/';
450
        }
451 3
        if (!is_array($this->slugs) || !array_key_exists($slug, $this->slugs)) {
0 ignored issues
show
introduced by
The condition is_array($this->slugs) is always true.
Loading history...
452 1
            throw new RouterException(t('No existe la ruta especificada'));
0 ignored issues
show
Bug introduced by
It seems like t('No existe la ruta especificada') can also be of type string; however, parameter $message of PSFS\base\exception\RouterException::__construct() does only seem to accept null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

452
            throw new RouterException(/** @scrutinizer ignore-type */ t('No existe la ruta especificada'));
Loading history...
453
        }
454 3
        $url = $absolute ? Request::getInstance()->getRootUrl() . $this->slugs[$slug] : $this->slugs[$slug];
455 3
        if (!empty($params)) {
456
            foreach ($params as $key => $value) {
457
                $url = str_replace('{' . $key . '}', $value, $url);
458
            }
459 3
        } elseif (!empty($this->routing[$this->slugs[$slug]]['default'])) {
460 3
            $url = $absolute ? Request::getInstance()->getRootUrl() . $this->routing[$this->slugs[$slug]]['default'] : $this->routing[$this->slugs[$slug]]['default'];
461
        }
462
463 3
        return preg_replace('/(GET|POST|PUT|DELETE|ALL)\#\|\#/', '', $url);
464
    }
465
466
    /**
467
     * @return array
468
     */
469 2
    public function getDomains()
470
    {
471 2
        return $this->domains ?: [];
472
    }
473
474
    /**
475
     * @param string $class
476
     * @param string $method
477
     */
478 1
    private function checkPreActions($class, $method) {
479 1
        $preAction = 'pre' . ucfirst($method);
480 1
        if(method_exists($class, $preAction)) {
481
            Inspector::stats('[Router] Pre action invoked ');
482
            try {
483
                if(false === call_user_func_array([$class, $preAction])) {
0 ignored issues
show
Bug introduced by
The call to call_user_func_array() has too few arguments starting with param_arr. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

483
                if(false === /** @scrutinizer ignore-call */ call_user_func_array([$class, $preAction])) {

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
484
                    Logger::log(t('Pre action failed'), LOG_ERR, [error_get_last()]);
485
                    error_clear_last();
486
                }
487
            } catch (\Exception $e) {
488
                Logger::log($e->getMessage(), LOG_ERR, [$class, $method]);
489
            }
490
        }
491 1
    }
492
493
    /**
494
     * @param string $route
495
     * @param array $action
496
     * @param string $class
497
     * @param array $params
498
     * @return mixed
499
     * @throws exception\GeneratorException
500
     * @throws ConfigException
501
     */
502 1
    protected function executeCachedRoute($route, $action, $class, $params = NULL)
503
    {
504 1
        Inspector::stats('[Router] Executing route ' . $route);
505 1
        $action['params'] = array_merge($action['params'], $params, Request::getInstance()->getQueryParams());
506 1
        Security::getInstance()->setSessionKey(Cache::CACHE_SESSION_VAR, $action);
507 1
        $cache = Cache::needCache();
508 1
        $execute = TRUE;
509 1
        $return = null;
510 1
        if (FALSE !== $cache && $action['http'] === 'GET' && Config::getParam('debug') === FALSE) {
511
            list($path, $cacheDataName) = $this->cache->getRequestCacheHash();
512
            $cachedData = $this->cache->readFromCache('json' . DIRECTORY_SEPARATOR . $path . $cacheDataName, $cache);
0 ignored issues
show
Bug introduced by
It seems like $cache can also be of type true; however, parameter $expires of PSFS\base\Cache::readFromCache() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

512
            $cachedData = $this->cache->readFromCache('json' . DIRECTORY_SEPARATOR . $path . $cacheDataName, /** @scrutinizer ignore-type */ $cache);
Loading history...
513
            if (NULL !== $cachedData) {
514
                $headers = $this->cache->readFromCache('json' . DIRECTORY_SEPARATOR . $path . $cacheDataName . '.headers', $cache, null, Cache::JSON);
515
                Template::getInstance()->renderCache($cachedData, $headers);
516
                $execute = FALSE;
517
            }
518
        }
519 1
        if ($execute) {
520 1
            Inspector::stats('[Router] Start executing action ' . $route);
521 1
            $this->checkPreActions($class, $action['method']);
522 1
            $return = call_user_func_array([$class, $action['method']], $params);
0 ignored issues
show
Bug introduced by
It seems like $params can also be of type null; however, parameter $param_arr of call_user_func_array() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

522
            $return = call_user_func_array([$class, $action['method']], /** @scrutinizer ignore-type */ $params);
Loading history...
523 1
            if (false === $return) {
524
                Logger::log(t('An error occurred trying to execute the action'), LOG_ERR, [error_get_last()]);
525
            }
526
        }
527 1
        return $return;
528
    }
529
530
    /**
531
     * Parse slugs to create translations
532
     *
533
     * @param string $absoluteTranslationFileName
534
     */
535 1
    private function generateSlugs($absoluteTranslationFileName)
536
    {
537 1
        $translations = I18nHelper::generateTranslationsFile($absoluteTranslationFileName);
538 1
        foreach ($this->routing as $key => &$info) {
539 1
            $keyParts = explode('#|#', $key);
540 1
            $keyParts = array_key_exists(1, $keyParts) ? $keyParts[1] : $keyParts[0];
541 1
            $slug = RouterHelper::slugify($keyParts);
542 1
            if (NULL !== $slug && !array_key_exists($slug, $translations)) {
543 1
                $translations[$slug] = $info['label'];
544 1
                file_put_contents($absoluteTranslationFileName, "\$translations[\"{$slug}\"] = t(\"{$info['label']}\");\n", FILE_APPEND);
545
            }
546 1
            $this->slugs[$slug] = $key;
547 1
            $info['slug'] = $slug;
548
        }
549 1
    }
550
551
    /**
552
     * @param bool $hydrateRoute
553
     * @param $modulePath
554
     * @param $externalModulePath
555
     */
556
    private function loadExternalAutoloader($hydrateRoute, SplFileInfo $modulePath, $externalModulePath)
557
    {
558
        $extModule = $modulePath->getBasename();
559
        $moduleAutoloader = realpath($externalModulePath . DIRECTORY_SEPARATOR . $extModule . DIRECTORY_SEPARATOR . 'autoload.php');
560
        if(file_exists($moduleAutoloader)) {
561
            include_once $moduleAutoloader;
562
            if ($hydrateRoute) {
563
                $this->routing = $this->inspectDir($externalModulePath . DIRECTORY_SEPARATOR . $extModule, '\\' . $extModule, $this->routing);
564
            }
565
        }
566
    }
567
568
    /**
569
     * @param $hydrateRoute
570
     * @param $module
571
     * @return mixed
572
     */
573 1
    private function loadExternalModule($hydrateRoute, $module)
574
    {
575
        try {
576 1
            $module = preg_replace('/(\\\|\/)/', DIRECTORY_SEPARATOR, $module);
577 1
            $externalModulePath = VENDOR_DIR . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'src';
578 1
            if(file_exists($externalModulePath)) {
579
                $externalModule = $this->finder->directories()->in($externalModulePath)->depth(0);
580
                if($externalModule->hasResults()) {
581
                    foreach ($externalModule->getIterator() as $modulePath) {
582 1
                        $this->loadExternalAutoloader($hydrateRoute, $modulePath, $externalModulePath);
583
                    }
584
                }
585
            }
586
        } catch (\Exception $e) {
587
            Logger::log($e->getMessage(), LOG_WARNING);
588
            $module = null;
589
        }
590 1
        return $module;
591
    }
592
593
}
594