Passed
Push — master ( cf70c6...6539c2 )
by Fran
07:46
created

Router::getExternalModules()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.1481

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 7
ccs 4
cts 6
cp 0.6667
crap 2.1481
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace PSFS\base;
3
4
use PSFS\base\config\Config;
5
use PSFS\base\exception\AccessDeniedException;
6
use PSFS\base\exception\ConfigException;
7
use PSFS\base\exception\RouterException;
8
use PSFS\base\types\helpers\AdminHelper;
9
use PSFS\base\types\helpers\GeneratorHelper;
10
use PSFS\base\types\helpers\I18nHelper;
11
use PSFS\base\types\helpers\RequestHelper;
12
use PSFS\base\types\helpers\RouterHelper;
13
use PSFS\base\types\helpers\SecurityHelper;
14
use PSFS\base\types\traits\SingletonTrait;
15
use PSFS\controller\base\Admin;
16
use PSFS\services\AdminServices;
17
use Symfony\Component\Finder\Finder;
18
19
20
/**
21
 * Class Router
22
 * @package PSFS
23
 */
24
class Router
25
{
26
    use SingletonTrait;
27
28
    protected $routing;
29
    protected $slugs;
30
    private $domains;
31
    /**
32
     * @var Finder $finder
33
     */
34
    private $finder;
35
    /**
36
     * @var \PSFS\base\Cache $cache
37
     */
38
    private $cache;
39
    /**
40
     * @var bool headersSent
41
     */
42
    protected $headersSent = false;
43
    /**
44
     * @var int
45
     */
46
    protected $cacheType = Cache::JSON;
47
48
    /**
49
     * Constructor Router
50
     * @throws ConfigException
51
     */
52 1
    public function __construct()
53
    {
54 1
        $this->finder = new Finder();
55 1
        $this->cache = Cache::getInstance();
56 1
        $this->init();
57 1
    }
58
59
    /**
60
     * Inicializador Router
61
     * @throws ConfigException
62
     */
63 1
    public function init()
64
    {
65 1
        list($this->routing, $this->slugs) = $this->cache->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . "urls.json", $this->cacheType, TRUE);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 147 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
66 1
        $this->domains = $this->cache->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . "domains.json", $this->cacheType, TRUE);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 130 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
67 1
        if (empty($this->routing) || Config::getInstance()->getDebugMode()) {
68 1
            $this->debugLoad();
69 1
        }
70 1
        $this->checkExternalModules(false);
71 1
    }
72
73
    /**
74
     * Load routes and domains and store them
75
     */
76 1
    private function debugLoad() {
77 1
        Logger::log('Begin routes load', LOG_DEBUG);
78 1
        $this->hydrateRouting();
79 1
        $this->simpatize();
80 1
        Logger::log('End routes load', LOG_DEBUG);
81 1
    }
82
83
    /**
84
     * Método que deriva un error HTTP de página no encontrada
85
     *
86
     * @param \Exception $e
87
     * @param boolean $isJson
88
     *
89
     * @return string HTML
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
90
     */
91 1
    public function httpNotFound(\Exception $e = NULL, $isJson = false)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $e. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
92
    {
93
        Logger::log('Throw not found exception');
94
        if (NULL === $e) {
95
            Logger::log('Not found page throwed without previous exception', LOG_WARNING);
96
            $e = new \Exception(_('Page not found'), 404);
97
        }
98
        $template = Template::getInstance()->setStatus($e->getCode());
99
        if (preg_match('/json/i', Request::getInstance()->getServer('CONTENT_TYPE')) || $isJson) {
100
            return $template->output(json_encode(array(
101 1
                "success" => FALSE,
102
                "error" => $e->getMessage(),
103
            )), 'application/json');
104
        } else {
105
            return $template->render('error.html.twig', array(
106
                'exception' => $e,
107
                'trace' => $e->getTraceAsString(),
108
                'error_page' => TRUE,
109
            ));
110
        }
111
    }
112
113
    /**
114
     * Método que devuelve las rutas
115
     * @return string|null
116
     */
117 1
    public function getSlugs()
118
    {
119 1
        return $this->slugs;
120
    }
121
122
    /**
123
     * @return mixed
124
     */
125 2
    public function getRoutes() {
126 2
        return $this->routing;
127
    }
128
129
    /**
130
     * Method that extract all routes in the platform
131
     * @return array
132
     */
133 1
    public function getAllRoutes()
134
    {
135 1
        $routes = [];
136 1
        foreach ($this->getRoutes() as $path => $route) {
137 1
            if (array_key_exists('slug', $route)) {
138 1
                $routes[$route['slug']] = $path;
139 1
            }
140 1
        }
141 1
        return $routes;
142
    }
143
144
    /**
145
     * Método que calcula el objeto a enrutar
146
     *
147
     * @param string|null $route
148
     *
149
     * @throws \Exception
150
     * @return string HTML
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
151
     */
152 1
    public function execute($route)
153
    {
154 1
        Logger::log('Executing the request');
155
        try {
156
            //Check CORS for requests
157 1
            RequestHelper::checkCORS();
158
            // Checks restricted access
159 1
            SecurityHelper::checkRestrictedAccess($route);
160
            //Search action and execute
161 1
            $this->searchAction($route);
162 1
        } catch (AccessDeniedException $e) {
163
            Logger::log(_('Solicitamos credenciales de acceso a zona restringida'));
164
            return Admin::staticAdminLogon($route);
165 1
        } catch (RouterException $r) {
166 1
            Logger::log($r->getMessage(), LOG_WARNING);
167 1
        } catch (\Exception $e) {
168
            Logger::log($e->getMessage(), LOG_ERR);
169
            throw $e;
170
        }
171
172 1
        throw new RouterException(_("Página no encontrada"), 404);
173
    }
174
175
    /**
176
     * Método que busca el componente que ejecuta la ruta
177
     *
178
     * @param string $route
179
     *
180
     * @throws \PSFS\base\exception\RouterException
181
     */
182 1
    protected function searchAction($route)
183
    {
184 1
        Logger::log('Searching action to execute: ' . $route, LOG_INFO);
185
        //Revisamos si tenemos la ruta registrada
186 1
        $parts = parse_url($route);
187 1
        $path = (array_key_exists('path', $parts)) ? $parts['path'] : $route;
188 1
        $httpRequest = Request::getInstance()->getMethod();
189 1
        foreach ($this->routing as $pattern => $action) {
190 1
            list($httpMethod, $routePattern) = RouterHelper::extractHttpRoute($pattern);
191 1
            $matched = RouterHelper::matchRoutePattern($routePattern, $path);
192 1
            if ($matched && ($httpMethod === "ALL" || $httpRequest === $httpMethod) && RouterHelper::compareSlashes($routePattern, $path)) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 140 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
193
                $get = RouterHelper::extractComponents($route, $routePattern);
194
                /** @var $class \PSFS\base\types\Controller */
195
                $class = RouterHelper::getClassToCall($action);
196
                try {
197
                    $this->executeCachedRoute($route, $action, $class, $get);
198
                } catch (\Exception $e) {
199
                    Logger::log($e->getMessage(), LOG_ERR);
200
                    throw new \RuntimeException($e->getMessage(), 404, $e);
201
                }
202
            }
203 1
        }
204 1
        throw new RouterException(_("Ruta no encontrada"));
205
    }
206
207
    /**
208
     * Método que manda las cabeceras de autenticación
209
     * @return string HTML
210
     */
211
    protected function sentAuthHeader()
212
    {
213
        return AdminServices::getInstance()->setAdminHeaders();
214
    }
215
216
    /**
217
     * @return string|null
218
     */
219 1
    private function getExternalModules() {
220 1
        $externalModules = Config::getParam('modules.extend', '');
221 1
        if(Config::getParam('psfs.auth', false)) {
222
            $externalModules .= ',psfs/auth';
223
        }
224 1
        return $externalModules;
225
    }
226
227
    /**
228
     * Method that check if the proyect has sub project to include
229
     * @param boolean $hydrateRoute
230
     */
231 1
    private function checkExternalModules($hydrateRoute = true)
232
    {
233 1
        $externalModules = $this->getExternalModules();
234 1
        if (strlen($externalModules)) {
235
            $externalModules = explode(',', $externalModules);
236
            foreach ($externalModules as &$module) {
237
                $module = preg_replace('/(\\\|\/)/', DIRECTORY_SEPARATOR, $module);
238
                $externalModulePath = VENDOR_DIR . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'src';
239
                if (file_exists($externalModulePath)) {
240
                    $externalModule = $this->finder->directories()->in($externalModulePath)->depth(0);
241
                    if (!empty($externalModule)) {
242
                        foreach ($externalModule as $modulePath) {
243
                            $extModule = $modulePath->getBasename();
244
                            $moduleAutoloader = realpath($externalModulePath . DIRECTORY_SEPARATOR . $extModule . DIRECTORY_SEPARATOR . 'autoload.php');
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 152 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
245
                            if (file_exists($moduleAutoloader)) {
246
                                @include $moduleAutoloader;
247
                                if ($hydrateRoute) {
248
                                    $this->routing = $this->inspectDir($externalModulePath . DIRECTORY_SEPARATOR . $extModule, '\\' . $extModule, $this->routing);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 162 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
249
                                }
250
                            }
251
                        }
252
                    }
253
                }
254
            }
255
        }
256 1
    }
257
258
    /**
259
     * Method that gather all the routes in the project
260
     */
261 1
    private function generateRouting()
262
    {
263 1
        $base = SOURCE_DIR;
264 1
        $modulesPath = realpath(CORE_DIR);
265 1
        $this->routing = $this->inspectDir($base, "PSFS", array());
266 1
        $this->checkExternalModules();
267 1
        if (file_exists($modulesPath)) {
268
            $modules = $this->finder->directories()->in($modulesPath)->depth(0);
269
            foreach ($modules as $modulePath) {
270
                $module = $modulePath->getBasename();
271
                $this->routing = $this->inspectDir($modulesPath . DIRECTORY_SEPARATOR . $module, $module, $this->routing);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
272
            }
273
        }
274 1
        $this->cache->storeData(CONFIG_DIR . DIRECTORY_SEPARATOR . "domains.json", $this->domains, Cache::JSON, TRUE);
275 1
    }
276
277
    /**
278
     * Método que regenera el fichero de rutas
279
     * @throws ConfigException
280
     */
281 1
    public function hydrateRouting()
282
    {
283 1
        $this->generateRouting();
284 1
        $home = Config::getInstance()->get('home.action');
285 1
        if (NULL !== $home || $home !== '') {
286 1
            $home_params = NULL;
287 1
            foreach ($this->routing as $pattern => $params) {
288 1
                list($method, $route) = RouterHelper::extractHttpRoute($pattern);
289 1
                if (preg_match("/" . preg_quote($route, "/") . "$/i", "/" . $home)) {
290
                    $home_params = $params;
291
                }
292 1
            }
293 1
            if (NULL !== $home_params) {
294
                $this->routing['/'] = $home_params;
295
            }
296 1
        }
297 1
    }
298
299
    /**
300
     * Método que inspecciona los directorios en busca de clases que registren rutas
301
     *
302
     * @param string $origen
303
     * @param string $namespace
304
     * @param array $routing
305
     *
306
     * @return array
307
     * @throws ConfigException
308
     */
309 1
    private function inspectDir($origen, $namespace = 'PSFS', $routing = [])
310
    {
311 1
        $files = $this->finder->files()->in($origen)->path('/(controller|api)/i')->depth(1)->name("*.php");
312 1
        foreach ($files as $file) {
313 1
            $filename = str_replace("/", '\\', str_replace($origen, '', $file->getPathname()));
314 1
            $routing = $this->addRouting($namespace . str_replace('.php', '', $filename), $routing, $namespace);
315 1
        }
316 1
        $this->finder = new Finder();
317
318 1
        return $routing;
319
    }
320
321
    /**
322
     * Checks that a namespace exists
323
     * @param string $namespace
324
     * @return bool
325
     */
326 1
    public static function exists($namespace)
327
    {
328 1
        return (class_exists($namespace) || interface_exists($namespace) || trait_exists($namespace));
329
    }
330
331
    /**
332
     * Método que añade nuevas rutas al array de referencia
333
     *
334
     * @param string $namespace
335
     * @param array $routing
336
     * @param string $module
337
     *
338
     * @return array
339
     * @throws ConfigException
340
     */
341 1
    private function addRouting($namespace, &$routing, $module = 'PSFS')
342
    {
343 1
        if (self::exists($namespace)) {
344 1
            $reflection = new \ReflectionClass($namespace);
345 1
            if (FALSE === $reflection->isAbstract() && FALSE === $reflection->isInterface()) {
346 1
                $this->extractDomain($reflection);
347 1
                $classComments = $reflection->getDocComment();
348 1
                preg_match('/@api\ (.*)\n/im', $classComments, $apiPath);
349 1
                $api = '';
350 1
                if (count($apiPath)) {
351
                    $api = array_key_exists(1, $apiPath) ? $apiPath[1] : $api;
352
                }
353 1
                foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
354 1
                    if (preg_match('/@route\ /i', $method->getDocComment())) {
355 1
                        list($route, $info) = RouterHelper::extractRouteInfo($method, str_replace('\\', '', $api), str_replace('\\', '', $module));
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 147 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
356
357 1
                        if (null !== $route && null !== $info) {
358 1
                            $info['class'] = $namespace;
359 1
                            $routing[$route] = $info;
360 1
                        }
361 1
                    }
362 1
                }
363 1
            }
364 1
        }
365
366 1
        return $routing;
367
    }
368
369
    /**
370
     * Método que extrae de la ReflectionClass los datos necesarios para componer los dominios en los templates
371
     *
372
     * @param \ReflectionClass $class
373
     *
374
     * @return Router
375
     * @throws ConfigException
376
     */
377 1
    protected function extractDomain(\ReflectionClass $class)
378
    {
379
        //Calculamos los dominios para las plantillas
380 1
        if ($class->hasConstant("DOMAIN") && !$class->isAbstract()) {
381 1
            if (!$this->domains) {
382 1
                $this->domains = [];
383 1
            }
384 1
            $domain = "@" . $class->getConstant("DOMAIN") . "/";
385 1
            if (!array_key_exists($domain, $this->domains)) {
386 1
                $this->domains[$domain] = RouterHelper::extractDomainInfo($class, $domain);
387 1
            }
388 1
        }
389
390 1
        return $this;
391
    }
392
393
    /**
394
     * Método que genera las urls amigables para usar dentro del framework
395
     * @return Router
396
     */
397 1
    public function simpatize()
398
    {
399 1
        $translationFileName = "translations" . DIRECTORY_SEPARATOR . "routes_translations.php";
400 1
        $absoluteTranslationFileName = CACHE_DIR . DIRECTORY_SEPARATOR . $translationFileName;
401 1
        $this->generateSlugs($absoluteTranslationFileName);
402 1
        GeneratorHelper::createDir(CONFIG_DIR);
403 1
        Cache::getInstance()->storeData(CONFIG_DIR . DIRECTORY_SEPARATOR . "urls.json", array($this->routing, $this->slugs), Cache::JSON, TRUE);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 144 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
404
405 1
        return $this;
406
    }
407
408
    /**
409
     * Método que devuelve una ruta del framework
410
     *
411
     * @param string $slug
412
     * @param boolean $absolute
413
     * @param array $params
414
     *
415
     * @return string|null
416
     * @throws RouterException
417
     */
418 2
    public function getRoute($slug = '', $absolute = FALSE, $params = [])
419
    {
420 2
        if (strlen($slug) === 0) {
421
            return ($absolute) ? Request::getInstance()->getRootUrl() . '/' : '/';
422
        }
423 2
        if (!is_array($this->slugs) || !array_key_exists($slug, $this->slugs)) {
424
            throw new RouterException(_("No existe la ruta especificada"));
425
        }
426 2
        $url = ($absolute) ? Request::getInstance()->getRootUrl() . $this->slugs[$slug] : $this->slugs[$slug];
427 2
        if (!empty($params)) foreach ($params as $key => $value) {
428
            $url = str_replace("{" . $key . "}", $value, $url);
429 2
        } elseif (!empty($this->routing[$this->slugs[$slug]]["default"])) {
430 2
            $url = ($absolute) ? Request::getInstance()->getRootUrl() . $this->routing[$this->slugs[$slug]]["default"] : $this->routing[$this->slugs[$slug]]["default"];
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 168 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
431 2
        }
432
433 2
        return preg_replace('/(GET|POST|PUT|DELETE|ALL)\#\|\#/', '', $url);
434
    }
435
436
    /**
437
     * Método que devuelve las rutas de administración
438
     * @deprecated
439
     * @return array
440
     */
441
    public function getAdminRoutes()
442
    {
443
        return AdminHelper::getAdminRoutes($this->routing);
444
    }
445
446
    /**
447
     * Método que devuelve le controlador del admin
448
     * @deprecated
449
     * @return Admin
450
     */
451
    public function getAdmin()
452
    {
453
        return Admin::getInstance();
454
    }
455
456
    /**
457
     * Método que extrae los dominios
458
     * @return array
459
     */
460 1
    public function getDomains()
461
    {
462 1
        return $this->domains ?: [];
463
    }
464
465
    /**
466
     * Método que ejecuta una acción del framework y revisa si lo tenemos cacheado ya o no
467
     *
468
     * @param string $route
469
     * @param array|null $action
470
     * @param types\Controller $class
471
     * @param array $params
0 ignored issues
show
Documentation introduced by
Should the type for parameter $params not be array|null? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
472
     */
473
    protected function executeCachedRoute($route, $action, $class, $params = NULL)
474
    {
475
        Logger::log('Executing route ' . $route, LOG_INFO);
476
        Security::getInstance()->setSessionKey("__CACHE__", $action);
477
        $cache = Cache::needCache();
478
        $execute = TRUE;
479
        if (FALSE !== $cache && Config::getInstance()->getDebugMode() === FALSE) {
480
            list($path, $cacheDataName) = $this->cache->getRequestCacheHash();
481
            $cachedData = $this->cache->readFromCache("json" . DIRECTORY_SEPARATOR . $path . $cacheDataName,
482
                $cache, function () {
0 ignored issues
show
Bug introduced by
It seems like $cache defined by \PSFS\base\Cache::needCache() on line 477 can also be of type boolean; however, PSFS\base\Cache::readFromCache() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
483
                });
484
            if (NULL !== $cachedData) {
485
                $headers = $this->cache->readFromCache("json" . DIRECTORY_SEPARATOR . $path . $cacheDataName . ".headers",
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
486
                    $cache, function () {
0 ignored issues
show
Bug introduced by
It seems like $cache defined by \PSFS\base\Cache::needCache() on line 477 can also be of type boolean; however, PSFS\base\Cache::readFromCache() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
487
                    }, Cache::JSON);
488
                Template::getInstance()->renderCache($cachedData, $headers);
489
                $execute = FALSE;
490
            }
491
        }
492
        if ($execute) {
493
            Logger::log(_('Start executing action'), LOG_DEBUG);
494
            if (false === call_user_func_array(array($class, $action['method']), $params)) {
495
                Logger::log(_('An error ocurred trying to execute the action'), LOG_ERR, [error_get_last()]);
496
            }
497
        }
498
    }
499
500
    /**
501
     * Parse slugs to create translations
502
     *
503
     * @param string $absoluteTranslationFileName
504
     */
505 1
    private function generateSlugs($absoluteTranslationFileName)
506
    {
507 1
        $translations = I18nHelper::generateTranslationsFile($absoluteTranslationFileName);
508 1
        foreach ($this->routing as $key => &$info) {
509 1
            $keyParts = $key;
510 1
            if (FALSE === strstr("#|#", $key)) {
511 1
                $keyParts = explode("#|#", $key);
512 1
                $keyParts = array_key_exists(1, $keyParts) ? $keyParts[1] : '';
513 1
            }
514 1
            $slug = RouterHelper::slugify($keyParts);
515 1
            if (NULL !== $slug && !array_key_exists($slug, $translations)) {
516 1
                $translations[$slug] = $key;
517 1
                file_put_contents($absoluteTranslationFileName, "\$translations[\"{$slug}\"] = _(\"{$slug}\");\n", FILE_APPEND);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 128 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
518 1
            }
519 1
            $this->slugs[$slug] = $key;
520 1
            $info["slug"] = $slug;
521 1
        }
522 1
    }
523
524
}
525