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

Router::addRouting()   B

Complexity

Conditions 11
Paths 6

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 11.1412

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 18
c 1
b 0
f 0
nc 6
nop 3
dl 0
loc 29
ccs 17
cts 19
cp 0.8947
crap 11.1412
rs 7.3166

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 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