Passed
Push — master ( 0ee5cf...8209bc )
by Fran
02:47
created

Router::getRoute()   B

Complexity

Conditions 10
Paths 11

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 10.4632

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 10
eloc 11
c 5
b 0
f 0
nc 11
nop 3
dl 0
loc 18
ccs 10
cts 12
cp 0.8333
crap 10.4632
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace PSFS\base;
3
4
use Exception;
5
use InvalidArgumentException;
6
use PSFS\base\config\Config;
7
use PSFS\base\dto\JsonResponse;
8
use PSFS\base\exception\AccessDeniedException;
9
use PSFS\base\exception\AdminCredentialsException;
10
use PSFS\base\exception\ConfigException;
11
use PSFS\base\exception\RouterException;
12
use PSFS\base\types\Controller;
13
use PSFS\base\types\helpers\AnnotationHelper;
14
use PSFS\base\types\helpers\GeneratorHelper;
15
use PSFS\base\types\helpers\I18nHelper;
16
use PSFS\base\types\helpers\Inspector;
17
use PSFS\base\types\helpers\RouterHelper;
18
use PSFS\base\types\helpers\SecurityHelper;
19
use PSFS\base\types\traits\SingletonTrait;
20
use PSFS\controller\base\Admin;
21
use PSFS\services\AdminServices;
22
use ReflectionClass;
23
use ReflectionException;
24
use ReflectionMethod;
25
use Symfony\Component\Finder\Finder;
26
use Symfony\Component\Finder\SplFileInfo;
27
28
/**
29
 * Class Router
30
 * @package PSFS
31
 */
32
class Router
33
{
34
    use SingletonTrait;
35
36
    /**
37
     * @var array
38
     */
39
    private $routing = [];
40
    /**
41
     * @var array
42
     */
43
    private $slugs = [];
44
    /**
45
     * @var array
46
     */
47
    private $domains = [];
48
    /**
49
     * @var Finder $finder
50
     */
51
    private $finder;
52
    /**
53
     * @var Cache $cache
54
     */
55
    private $cache;
56
    /**
57
     * @var bool headersSent
58
     */
59
    protected $headersSent = false;
60
    /**
61
     * @var int
62
     */
63
    protected $cacheType = Cache::JSON;
64
65
    /**
66
     * Router constructor.
67
     * @throws exception\GeneratorException
68
     * @throws ConfigException
69
     * @throws InvalidArgumentException
70
     * @throws ReflectionException
71
     */
72 1
    public function __construct()
73
    {
74 1
        $this->finder = new Finder();
75 1
        $this->cache = Cache::getInstance();
76 1
        $this->init();
77 1
    }
78
79
    /**
80
     * @throws exception\GeneratorException
81
     * @throws ConfigException
82
     * @throws InvalidArgumentException
83
     * @throws ReflectionException
84
     */
85 1
    public function init()
86
    {
87 1
        list($this->routing, $this->slugs) = $this->cache->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . 'urls.json', $this->cacheType, TRUE);
88 1
        if (empty($this->routing) || Config::getParam('debug', true)) {
89 1
            $this->debugLoad();
90
        } else {
91
            $this->domains = $this->cache->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . 'domains.json', $this->cacheType, TRUE);
92
        }
93 1
        $this->checkExternalModules(false);
94 1
        $this->setLoaded();
95 1
    }
96
97
    /**
98
     * @throws exception\GeneratorException
99
     * @throws ConfigException
100
     * @throws InvalidArgumentException
101
     * @throws ReflectionException
102
     */
103 1
    private function debugLoad() {
104 1
        Logger::log('Begin routes load');
105 1
        $this->hydrateRouting();
106 1
        $this->simpatize();
107 1
        Logger::log('End routes load');
108 1
    }
109
110
    /**
111
     * @param Exception|NULL $exception
112
     * @param bool $isJson
113
     * @return string
114
     * @throws RouterException
115
     * @throws exception\GeneratorException
116
     */
117
    public function httpNotFound(Exception $exception = NULL, $isJson = false)
118
    {
119
        Inspector::stats('[Router] Throw not found exception', Inspector::SCOPE_DEBUG);
120
        if (NULL === $exception) {
121
            Logger::log('Not found page thrown without previous exception', LOG_WARNING);
122
            $exception = new Exception(t('Page not found'), 404);
123
        }
124
        $template = Template::getInstance()->setStatus($exception->getCode());
125
        if ($isJson || false !== stripos(Request::getInstance()->getServer('CONTENT_TYPE'), 'json')) {
126
            $response = new JsonResponse(null, false, 0, 0, $exception->getMessage());
127
            return $template->output(json_encode($response), 'application/json');
128
        }
129
130
        $notFoundRoute = Config::getParam('route.404');
131
        if(null !== $notFoundRoute) {
132
            Request::getInstance()->redirect($this->getRoute($notFoundRoute, true));
133
        } else {
134
            return $template->render('error.html.twig', array(
135
                'exception' => $exception,
136
                'trace' => $exception->getTraceAsString(),
137
                'error_page' => TRUE,
138
            ));
139
        }
140
    }
141
142
    /**
143
     * @return array
144
     */
145 1
    public function getSlugs()
146
    {
147 1
        return $this->slugs;
148
    }
149
150
    /**
151
     * @return array
152
     */
153 2
    public function getRoutes() {
154 2
        return $this->routing;
155
    }
156
157
    /**
158
     * Method that extract all routes in the platform
159
     * @return array
160
     */
161 1
    public function getAllRoutes()
162
    {
163 1
        $routes = [];
164 1
        foreach ($this->getRoutes() as $path => $route) {
165 1
            if (array_key_exists('slug', $route)) {
166 1
                $routes[$route['slug']] = $path;
167
            }
168
        }
169 1
        return $routes;
170
    }
171
172
    /**
173
     * @param string|null $route
174
     *
175
     * @throws Exception
176
     * @return string HTML
177
     */
178 2
    public function execute($route)
179
    {
180 2
        Inspector::stats('[Router] Executing the request', Inspector::SCOPE_DEBUG);
181
        try {
182
            //Search action and execute
183 2
            return $this->searchAction($route);
184 1
        } catch (AccessDeniedException $e) {
185
            Logger::log(t('Solicitamos credenciales de acceso a zona restringida'), LOG_WARNING, ['file' => $e->getFile() . '[' . $e->getLine() . ']']);
186
            return Admin::staticAdminLogon($route);
187 1
        } catch (RouterException $r) {
188 1
            Logger::log($r->getMessage(), LOG_WARNING);
189
        } catch (Exception $e) {
190
            Logger::log($e->getMessage(), LOG_ERR);
191
            throw $e;
192
        }
193
194 1
        throw new RouterException(t('Página no encontrada'), 404);
195
    }
196
197
    /**
198
     * @param string $route
199
     * @return mixed
200
     * @throws AccessDeniedException
201
     * @throws AdminCredentialsException
202
     * @throws RouterException
203
     * @throws Exception
204
     */
205 2
    protected function searchAction($route)
206
    {
207 2
        Inspector::stats('[Router] Searching action to execute: ' . $route, Inspector::SCOPE_DEBUG);
208
        //Revisamos si tenemos la ruta registrada
209 2
        $parts = parse_url($route);
210 2
        $path = array_key_exists('path', $parts) ? $parts['path'] : $route;
211 2
        $httpRequest = Request::getInstance()->getMethod();
212 2
        foreach ($this->routing as $pattern => $action) {
213 2
            list($httpMethod, $routePattern) = RouterHelper::extractHttpRoute($pattern);
214 2
            $matched = RouterHelper::matchRoutePattern($routePattern, $path);
215 2
            if ($matched && ($httpMethod === 'ALL' || $httpRequest === $httpMethod) && RouterHelper::compareSlashes($routePattern, $path)) {
216
                // Checks restricted access
217 1
                SecurityHelper::checkRestrictedAccess($route);
218 1
                $get = RouterHelper::extractComponents($route, $routePattern);
219
                /** @var $class Controller */
220 1
                $class = RouterHelper::getClassToCall($action);
221
                try {
222 1
                    if($this->checkRequirements($action, $get)) {
223 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

223
                        return $this->executeCachedRoute($route, $action, /** @scrutinizer ignore-type */ $class, $get);
Loading history...
224
                    } else {
225
                        throw new RouterException(t('La ruta no es válida'), 400);
226
                    }
227
                } catch (Exception $e) {
228
                    Logger::log($e->getMessage(), LOG_ERR);
229 2
                    throw $e;
230
                }
231
            }
232
        }
233 1
        throw new RouterException(t('Ruta no encontrada'));
234
    }
235
236
    /**
237
     * @param array $action
238
     * @param array $params
239
     * @return bool
240
     */
241 1
    private function checkRequirements(array $action, $params = []) {
242 1
        Inspector::stats('[Router] Checking request requirements', Inspector::SCOPE_DEBUG);
243 1
        if(!empty($params) && !empty($action['requirements'])) {
244
            $checked = 0;
245
            foreach(array_keys($params) as $key) {
246
                if(in_array($key, $action['requirements'], true)) {
247
                    $checked++;
248
                }
249
            }
250
            $valid = count($action['requirements']) === $checked;
251
        } else {
252 1
            $valid = true;
253
        }
254 1
        return $valid;
255
    }
256
257
    /**
258
     * @return string HTML
259
     */
260
    protected function sentAuthHeader()
261
    {
262
        return AdminServices::getInstance()->setAdminHeaders();
263
    }
264
265
    /**
266
     * @return string|null
267
     */
268 1
    private function getExternalModules() {
269 1
        $externalModules = Config::getParam('modules.extend', '');
270 1
        $externalModules .= ',psfs/auth,psfs/nosql';
271 1
        return $externalModules;
272
    }
273
274
    /**
275
     * @param boolean $hydrateRoute
276
     */
277 1
    private function checkExternalModules($hydrateRoute = true)
278
    {
279 1
        $externalModules = $this->getExternalModules();
280 1
        if ('' !== $externalModules) {
281 1
            $externalModules = explode(',', $externalModules);
282 1
            foreach ($externalModules as &$module) {
283 1
                $module = $this->loadExternalModule($hydrateRoute, $module);
284
            }
285
        }
286 1
    }
287
288
    /**
289
     * @throws ConfigException
290
     * @throws InvalidArgumentException
291
     * @throws ReflectionException
292
     * @throws exception\GeneratorException
293
     */
294 1
    private function generateRouting()
295
    {
296 1
        $base = SOURCE_DIR;
297 1
        $modulesPath = realpath(CORE_DIR);
298 1
        $this->routing = $this->inspectDir($base, 'PSFS', array());
299 1
        $this->checkExternalModules();
300 1
        if (file_exists($modulesPath)) {
301
            $modules = $this->finder->directories()->in($modulesPath)->depth(0);
302
            if($modules->hasResults()) {
303
                foreach ($modules->getIterator() as $modulePath) {
304
                    $module = $modulePath->getBasename();
305
                    $this->routing = $this->inspectDir($modulesPath . DIRECTORY_SEPARATOR . $module, $module, $this->routing);
306
                }
307
            }
308
        }
309 1
        $this->cache->storeData(CONFIG_DIR . DIRECTORY_SEPARATOR . 'domains.json', $this->domains, Cache::JSON, TRUE);
310 1
    }
311
312
    /**
313
     * @throws exception\GeneratorException
314
     * @throws ConfigException
315
     * @throws InvalidArgumentException
316
     * @throws ReflectionException
317
     */
318 1
    public function hydrateRouting()
319
    {
320 1
        $this->generateRouting();
321 1
        $home = Config::getParam('home.action', 'admin');
322 1
        if (NULL !== $home || $home !== '') {
323 1
            $homeParams = NULL;
324 1
            foreach ($this->routing as $pattern => $params) {
325 1
                list($method, $route) = RouterHelper::extractHttpRoute($pattern);
326 1
                if (preg_match('/' . preg_quote($route, '/') . '$/i', '/' . $home)) {
327 1
                    $homeParams = $params;
328
                }
329 1
                unset($method);
330
            }
331 1
            if (NULL !== $homeParams) {
332 1
                $this->routing['/'] = $homeParams;
333
            }
334
        }
335 1
    }
336
337
    /**
338
     * @param string $origen
339
     * @param string $namespace
340
     * @param array $routing
341
     * @return array
342
     * @throws ReflectionException
343
     * @throws ConfigException
344
     * @throws InvalidArgumentException
345
     */
346 1
    private function inspectDir($origen, $namespace = 'PSFS', $routing = [])
347
    {
348 1
        $files = $this->finder->files()->in($origen)->path('/(controller|api)/i')->depth('< 3')->name('*.php');
349 1
        if($files->hasResults()) {
350 1
            foreach ($files->getIterator() as $file) {
351 1
                if($namespace !== 'PSFS' && method_exists($file, 'getRelativePathname')) {
352
                    $filename = '\\' . str_replace('/', '\\', str_replace($origen, '', $file->getRelativePathname()));
353
                } else {
354 1
                    $filename = str_replace('/', '\\', str_replace($origen, '', $file->getPathname()));
355
                }
356 1
                $routing = $this->addRouting($namespace . str_replace('.php', '', $filename), $routing, $namespace);
357
            }
358
        }
359 1
        $this->finder = new Finder();
360
361 1
        return $routing;
362
    }
363
364
    /**
365
     * @param string $namespace
366
     * @return bool
367
     */
368 3
    public static function exists($namespace)
369
    {
370 3
        return (class_exists($namespace) || interface_exists($namespace) || trait_exists($namespace));
371
    }
372
373
    /**
374
     * @param string $namespace
375
     * @param array $routing
376
     * @param string $module
377
     * @return array
378
     * @throws ReflectionException
379
     */
380 1
    private function addRouting($namespace, &$routing, $module = 'PSFS')
381
    {
382 1
        if (self::exists($namespace)) {
383 1
            if(I18nHelper::checkI18Class($namespace)) {
384
                return $routing;
385
            }
386 1
            $reflection = new ReflectionClass($namespace);
387 1
            if (false === $reflection->isAbstract() && FALSE === $reflection->isInterface()) {
388 1
                $this->extractDomain($reflection);
389 1
                $classComments = $reflection->getDocComment();
390 1
                $api = AnnotationHelper::extractApi($classComments);
391 1
                foreach ($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
392 1
                    $route = AnnotationHelper::extractRoute($method->getDocComment());
393 1
                    if (null !== $route) {
394 1
                        list($route, $info) = RouterHelper::extractRouteInfo($method, str_replace('\\', '', $api), str_replace('\\', '', $module));
395
396 1
                        if (null !== $route && null !== $info) {
397 1
                            $info['class'] = $namespace;
398 1
                            $routing[$route] = $info;
399
                        }
400
                    }
401
                }
402
            }
403
        }
404
405 1
        return $routing;
406
    }
407
408
    /**
409
     *
410
     * @param ReflectionClass $class
411
     *
412
     * @return Router
413
     * @throws ConfigException
414
     */
415 1
    protected function extractDomain(ReflectionClass $class)
416
    {
417
        //Calculamos los dominios para las plantillas
418 1
        if ($class->hasConstant('DOMAIN') && !$class->isAbstract()) {
419 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...
420 1
                $this->domains = [];
421
            }
422 1
            $domain = '@' . $class->getConstant('DOMAIN') . '/';
423 1
            if (!array_key_exists($domain, $this->domains)) {
424 1
                $this->domains[$domain] = RouterHelper::extractDomainInfo($class, $domain);
425
            }
426
        }
427
428 1
        return $this;
429
    }
430
431
    /**
432
     * @return $this
433
     * @throws exception\GeneratorException
434
     * @throws ConfigException
435
     */
436 1
    public function simpatize()
437
    {
438 1
        $translationFileName = 'translations' . DIRECTORY_SEPARATOR . 'routes_translations.php';
439 1
        $absoluteTranslationFileName = CACHE_DIR . DIRECTORY_SEPARATOR . $translationFileName;
440 1
        $this->generateSlugs($absoluteTranslationFileName);
441 1
        GeneratorHelper::createDir(CONFIG_DIR);
442 1
        Cache::getInstance()->storeData(CONFIG_DIR . DIRECTORY_SEPARATOR . 'urls.json', array($this->routing, $this->slugs), Cache::JSON, TRUE);
443
444 1
        return $this;
445
    }
446
447
    /**
448
     * @param string $slug
449
     * @param boolean $absolute
450
     * @param array $params
451
     *
452
     * @return string|null
453
     * @throws RouterException
454
     */
455 3
    public function getRoute($slug = '', $absolute = FALSE, array $params = [])
456
    {
457 3
        if ('' === $slug) {
458 1
            return $absolute ? Request::getInstance()->getRootUrl() . '/' : '/';
459
        }
460 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...
461 1
            throw new RouterException(t('No existe la ruta especificada'));
462
        }
463 3
        $url = $absolute ? Request::getInstance()->getRootUrl() . $this->slugs[$slug] : $this->slugs[$slug];
464 3
        if (!empty($params)) {
465
            foreach ($params as $key => $value) {
466
                $url = str_replace('{' . $key . '}', $value, $url);
467
            }
468 3
        } elseif (!empty($this->routing[$this->slugs[$slug]]['default'])) {
469 3
            $url = $absolute ? Request::getInstance()->getRootUrl() . $this->routing[$this->slugs[$slug]]['default'] : $this->routing[$this->slugs[$slug]]['default'];
470
        }
471
472 3
        return preg_replace('/(GET|POST|PUT|DELETE|ALL)\#\|\#/', '', $url);
473
    }
474
475
    /**
476
     * @return array
477
     */
478 2
    public function getDomains()
479
    {
480 2
        return $this->domains ?: [];
481
    }
482
483
    /**
484
     * @param string $class
485
     * @param string $method
486
     */
487 1
    private function checkPreActions($class, $method) {
488 1
        $preAction = 'pre' . ucfirst($method);
489 1
        if(method_exists($class, $preAction)) {
490
            Inspector::stats('[Router] Pre action invoked', Inspector::SCOPE_DEBUG);
491
            try {
492
                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

492
                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...
493
                    Logger::log(t('Pre action failed'), LOG_ERR, [error_get_last()]);
494
                    error_clear_last();
495
                }
496
            } catch (Exception $e) {
497
                Logger::log($e->getMessage(), LOG_ERR, [$class, $method]);
498
            }
499
        }
500 1
    }
501
502
    /**
503
     * @param string $route
504
     * @param array $action
505
     * @param string $class
506
     * @param array $params
507
     * @return mixed
508
     * @throws exception\GeneratorException
509
     * @throws ConfigException
510
     */
511 1
    protected function executeCachedRoute($route, $action, $class, $params = NULL)
512
    {
513 1
        Inspector::stats('[Router] Executing route ' . $route, Inspector::SCOPE_DEBUG);
514 1
        $action['params'] = array_merge($action['params'], $params, Request::getInstance()->getQueryParams());
515 1
        Security::getInstance()->setSessionKey(Cache::CACHE_SESSION_VAR, $action);
516 1
        $cache = Cache::needCache();
517 1
        $execute = TRUE;
518 1
        $return = null;
519 1
        if (FALSE !== $cache && $action['http'] === 'GET' && Config::getParam('debug') === FALSE) {
520
            list($path, $cacheDataName) = $this->cache->getRequestCacheHash();
521
            $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

521
            $cachedData = $this->cache->readFromCache('json' . DIRECTORY_SEPARATOR . $path . $cacheDataName, /** @scrutinizer ignore-type */ $cache);
Loading history...
522
            if (NULL !== $cachedData) {
523
                $headers = $this->cache->readFromCache('json' . DIRECTORY_SEPARATOR . $path . $cacheDataName . '.headers', $cache, null, Cache::JSON);
524
                Template::getInstance()->renderCache($cachedData, $headers);
525
                $execute = FALSE;
526
            }
527
        }
528 1
        if ($execute) {
529 1
            Inspector::stats('[Router] Start executing action ' . $route, Inspector::SCOPE_DEBUG);
530 1
            $this->checkPreActions($class, $action['method']);
531 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

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