Completed
Push — master ( 04bd65...4036d4 )
by Fran
09:06
created

Router   F

Complexity

Total Complexity 129

Size/Duplication

Total Lines 738
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 49.45%

Importance

Changes 50
Bugs 1 Features 0
Metric Value
c 50
b 1
f 0
dl 0
loc 738
ccs 181
cts 366
cp 0.4945
rs 3.4285
wmc 129
lcom 1
cbo 12

32 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 10 3
A __construct() 0 7 1
A httpNotFound() 0 22 3
A getSlugs() 0 4 1
C execute() 0 34 7
C checkCORS() 0 23 7
A compareSlashes() 0 11 3
C searchAction() 0 24 8
A sentAuthHeader() 0 4 1
A redirectLogin() 0 4 1
B checkRestrictedAccess() 0 13 7
B extractComponents() 0 17 5
C hydrateRouting() 0 23 7
A inspectDir() 0 11 2
D addRouting() 0 42 10
B extractDomain() 0 27 4
A simpatize() 0 10 1
B slugify() 0 25 3
B getRoute() 0 17 10
C getAdminRoutes() 0 31 11
A getAdmin() 0 4 1
A getDomains() 0 4 1
A getClassToCall() 0 7 3
A matchRoutePattern() 0 9 2
A extractHttpRoute() 0 10 2
B extractReflectionParams() 0 15 6
A extractReflectionHttpMethod() 0 6 2
A extractReflectionVisibility() 0 5 2
A extractReflectionCacheability() 0 6 2
B executeCachedRoute() 0 21 5
B generateSlugs() 0 20 6
A generateTranslationsFile() 0 11 2

How to fix   Complexity   

Complex Class

Complex classes like Router often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Router, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
    namespace PSFS\base;
4
5
    use PSFS\base\config\Config;
6
    use PSFS\base\exception\AccessDeniedException;
7
    use PSFS\base\exception\ConfigException;
8
    use PSFS\base\exception\RouterException;
9
    use PSFS\base\types\SingletonTrait;
10
    use PSFS\controller\Admin;
11
    use PSFS\services\AdminServices;
12
    use Symfony\Component\Finder\Finder;
13
14
15
    /**
16
     * Class Router
17
     * @package PSFS
18
     */
19
    class Router
20
    {
21
22
        use SingletonTrait;
23
24
        protected $routing;
25
        protected $slugs;
26
        private $domains;
27
        /**
28
         * @var Finder $finder
29
         */
30
        private $finder;
31
        /**
32
         * @var \PSFS\base\Cache $cache
33
         */
34
        private $cache;
35
        /**
36
         * @var \PSFS\base\Security $session
37
         */
38
        private $session;
39
        /**
40
         * @var bool headersSent
41
         */
42
        protected $headersSent = false;
43
44
        /**
45
         * Constructor Router
46
         * @throws ConfigException
47
         */
48 6
        public function __construct()
49
        {
50 6
            $this->finder = new Finder();
51 6
            $this->cache = Cache::getInstance();
52 6
            $this->session = Security::getInstance();
53 6
            $this->init();
54 6
        }
55
56
        /**
57
         * Inicializador Router
58
         * @throws ConfigException
59
         */
60 1
        public function init()
61
        {
62 1
            if (!file_exists(CONFIG_DIR . DIRECTORY_SEPARATOR . "urls.json") || Config::getInstance()->getDebugMode()) {
63 1
                $this->hydrateRouting();
64 1
                $this->simpatize();
65 1
            } else {
66
                list($this->routing, $this->slugs) = $this->cache->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . "urls.json", Cache::JSON, TRUE);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 150 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
                $this->domains = $this->cache->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . "domains.json", Cache::JSON, TRUE);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 133 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...
68
            }
69 1
        }
70
71
        /**
72
         * Método que deriva un error HTTP de página no encontrada
73
         *
74
         * @param \Exception $e
75
         *
76
         * @return string HTML
77
         */
78
        public function httpNotFound(\Exception $e = NULL)
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...
79
        {
80
            Logger::log('Throw not found exception');
81
            $template = Template::getInstance()->setStatus($e->getCode());
82
            if (preg_match('/json/i', Request::getInstance()->getServer('CONTENT_TYPE'))) {
83
                return $template->output(json_encode(array(
84
                    "success" => FALSE,
85
                    "error"   => $e->getMessage(),
86
                )), 'application/json');
87
            } else {
88
                if (NULL === $e) {
89
                    Logger::log('Not found page throwed without previus exception');
90
                    $e = new \Exception(_('Page not found'), 404);
91
                }
92
93
                return $template->render('error.html.twig', array(
94
                    'exception'  => $e,
95
                    'trace'      => $e->getTraceAsString(),
96
                    'error_page' => TRUE,
97
                ));
98
            }
99
        }
100
101
        /**
102
         * Método que devuelve las rutas
103
         * @return string|null
104
         */
105
        public function getSlugs()
106
        {
107
            return $this->slugs;
108
        }
109
110
        /**
111
         * Método que calcula el objeto a enrutar
112
         *
113
         * @param string $route
114
         *
115
         * @throws \Exception
116
         * @return string HTML
117
         */
118
        public function execute($route)
119
        {
120
            Logger::log('Executing the request');
121
            try {
122
                //Check CORS for requests
123
                $this->checkCORS();
124
                // Checks restricted access
125
                $this->checkRestrictedAccess($route);
126
                //Search action and execute
127
                return $this->searchAction($route);
128
            } catch (AccessDeniedException $e) {
129
                Logger::getInstance()->debugLog(_('Solicitamos credenciales de acceso a zona restringida'));
130
                if ('login' === Config::getInstance()->get('admin_login')) {
131
                    return $this->redirectLogin($route);
132
                } else {
133
                    return $this->sentAuthHeader();
134
                }
135
            } catch (RouterException $r) {
136
                if (FALSE !== preg_match('/\/$/', $route)) {
137
                    if (preg_match('/admin/', $route)) {
138
                        $default = Config::getInstance()->get('admin_action');
139
                    } else {
140
                        $default = Config::getInstance()->get('home_action');
141
                    }
142
143
                    return $this->execute($this->getRoute($default));
144
                }
145
            } catch (\Exception $e) {
146
                Logger::getInstance()->errorLog($e->getMessage());
147
                throw $e;
148
            }
149
150
            return $this->httpNotFound();
151
        }
152
153
        /**
154
         * Check CROS requests
155
         */
156
        private function checkCORS()
157
        {
158
            Logger::log('Checking CORS');
159
            $corsEnabled = Config::getInstance()->get('cors.enabled');
160
            $request = Request::getInstance();
161
            if (NULL !== $corsEnabled && null !== $request->getServer('HTTP_REFERER')) {
162
                if($corsEnabled == '*' || preg_match($corsEnabled, $request->getServer('HTTP_REFERER'))) {
163
                    if (!$this->headersSent) {
164
                        // TODO include this headers in Template class output method
165
                        header("Access-Control-Allow-Credentials: true");
166
                        header("Access-Control-Allow-Origin: *");
167
                        header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
168
                        header("Access-Control-Allow-Headers: Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Origin, Origin, X-Requested-With, Content-Type, Accept, Authorization, X-API-SEC-TOKEN, X-API-USER-TOKEN");
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 250 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...
169
                        $this->headersSent = true;
170
                    }
171
                    if(Request::getInstance()->getMethod() == 'OPTIONS') {
172
                        Logger::log('Returning OPTIONS header confirmation for CORS pre flight requests');
173
                        header( "HTTP/1.1 200 OK" );
174
                        exit();
175
                    }
176
                }
177
            }
178
        }
179
180
        /**
181
         * Function that checks if the long of the patterns match
182
         * @param $routePattern
183
         * @param $path
184
         * @return bool
185
         */
186
        private function compareSlashes($routePattern, $path) {
187
            $pattern_sep = count(explode('/', $routePattern));
188
            if(preg_match('/\/$/', $routePattern)) {
189
                $pattern_sep--;
190
            }
191
            $path_sep = count(explode('/', $path));
192
            if(preg_match('/\/$/', $path)) {
193
                $path_sep--;
194
            }
195
            return abs($pattern_sep - $path_sep) < 1;
196
        }
197
198
        /**
199
         * Método que busca el componente que ejecuta la ruta
200
         *
201
         * @param string $route
202
         *
203
         * @throws \Exception
204
         */
205
        protected function searchAction($route)
206
        {
207
            Logger::log('Searching action to execute');
208
            //Revisamos si tenemos la ruta registrada
209
            $parts = parse_url($route);
210
            $path = (array_key_exists('path', $parts)) ? $parts['path'] : $route;
211
            $httpRequest = Request::getInstance()->getMethod();
212
            foreach ($this->routing as $pattern => $action) {
213
                list($httpMethod, $routePattern) = $this->extractHttpRoute($pattern);
214
                $matched = $this->matchRoutePattern($routePattern, $path);
215
                if ($matched && ($httpMethod === "ALL" || $httpRequest === $httpMethod) && $this->compareSlashes($routePattern, $path)) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 137 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...
216
                    $get = $this->extractComponents($route, $routePattern);
217
                    /** @var $class \PSFS\base\types\Controller */
218
                    $class = $this->getClassToCall($action);
219
                    try {
220
                        return $this->executeCachedRoute($route, $action, $class, $get);
221
                    } catch (\Exception $e) {
222
                        Logger::log($e->getMessage(), LOG_ERR);
223
                        throw new RouterException($e->getMessage(), 404, $e);
224
                    }
225
                }
226
            }
227
            throw new RouterException(_("Ruta no encontrada"));
228
        }
229
230
        /**
231
         * Método que manda las cabeceras de autenticación
232
         * @return string HTML
233
         */
234
        protected function sentAuthHeader()
235
        {
236
            return AdminServices::getInstance()->setAdminHeaders();
237
        }
238
239
        /**
240
         * Método que redirige a la pantalla web del login
241
         *
242
         * @param string $route
243
         *
244
         * @return string HTML
245
         */
246
        public function redirectLogin($route)
247
        {
248
            return Admin::staticAdminLogon($route);
249
        }
250
251
        /**
252
         * Método que chequea el acceso a una zona restringida
253
         *
254
         * @param string $route
255
         *
256
         * @throws AccessDeniedException
257
         */
258
        protected function checkRestrictedAccess($route)
259
        {
260
            Logger::log('Checking admin zone');
261
            //Chequeamos si entramos en el admin
262
            if (!Config::getInstance()->checkTryToSaveConfig() && preg_match('/^\/admin/i', $route)
263
                || (!preg_match('/^\/(admin|setup\-admin)/i', $route) && NULL !== Config::getInstance()->get('restricted'))
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 123 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...
264
            ) {
265
                if (!preg_match('/^\/admin\/login/i', $route) && !$this->session->checkAdmin()) {
266
                    throw new AccessDeniedException();
267
                }
268
                Logger::log('Admin access granted');
269
            }
270
        }
271
272
        /**
273
         * Método que extrae de la url los parámetros REST
274
         *
275
         * @param string $route
276
         *
277
         * @param string $pattern
278
         *
279
         * @return array
280
         */
281
        protected function extractComponents($route, $pattern)
282
        {
283
            Logger::log('Extracting parts for the request to execute');
284
            $url = parse_url($route);
285
            $_route = explode("/", $url['path']);
286
            $_pattern = explode("/", $pattern);
287
            $get = array();
288
            if (!empty($_pattern)) foreach ($_pattern as $index => $component) {
289
                $_get = array();
290
                preg_match_all('/^\{(.*)\}$/i', $component, $_get);
291
                if (!empty($_get[1]) && isset($_route[$index])) {
292
                    $get[array_pop($_get[1])] = $_route[$index];
293
                }
294
            }
295
296
            return $get;
297
        }
298
299
        /**
300
         * Método que regenera el fichero de rutas
301
         * @throws ConfigException
302
         */
303 1
        public function hydrateRouting()
304
        {
305 1
            $base = SOURCE_DIR;
306 1
            $modules = realpath(CORE_DIR);
307 1
            $this->routing = $this->inspectDir($base, "PSFS", array());
308 1
            if (file_exists($modules)) {
309
                $this->routing = $this->inspectDir($modules, "", $this->routing);
310
            }
311 1
            $this->cache->storeData(CONFIG_DIR . DIRECTORY_SEPARATOR . "domains.json", $this->domains, Cache::JSON, TRUE);
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...
312 1
            $home = Config::getInstance()->get('home_action');
313 1
            if (NULL !== $home || $home !== '') {
314 1
                $home_params = NULL;
315 1
                foreach ($this->routing as $pattern => $params) {
316 1
                    list($method, $route) = $this->extractHttpRoute($pattern);
317 1
                    if (preg_match("/" . preg_quote($route, "/") . "$/i", "/" . $home)) {
318
                        $home_params = $params;
319
                    }
320 1
                }
321 1
                if (NULL !== $home_params) {
322
                    $this->routing['/'] = $home_params;
323
                }
324 1
            }
325 1
        }
326
327
        /**
328
         * Método que inspecciona los directorios en busca de clases que registren rutas
329
         *
330
         * @param string $origen
331
         * @param string $namespace
332
         * @param array $routing
333
         *
334
         * @return array
335
         * @throws ConfigException
336
         */
337 1
        private function inspectDir($origen, $namespace = 'PSFS', $routing)
338
        {
339 1
            $files = $this->finder->files()->in($origen)->path('/(controller|api)/i')->name("*.php");
340 1
            foreach ($files as $file) {
341 1
                $filename = str_replace("/", '\\', str_replace($origen, '', $file->getPathname()));
342 1
                $routing = $this->addRouting($namespace . str_replace('.php', '', $filename), $routing);
343 1
            }
344 1
            $this->finder = new Finder();
345
346 1
            return $routing;
347
        }
348
349
        /**
350
         * Método que añade nuevas rutas al array de referencia
351
         *
352
         * @param string $namespace
353
         * @param array $routing
354
         *
355
         * @return array
356
         * @throws ConfigException
357
         */
358 1
        private function addRouting($namespace, $routing)
359
        {
360 1
            if (class_exists($namespace)) {
361 1
                $reflection = new \ReflectionClass($namespace);
362 1
                if (FALSE === $reflection->isAbstract() && FALSE === $reflection->isInterface()) {
363 1
                    $this->extractDomain($reflection);
364 1
                    $classComments = $reflection->getDocComment();
365 1
                    preg_match('/@api\ (.*)\n/im', $classComments, $apiPath);
366 1
                    $api = '';
367 1
                    if (count($apiPath)) {
368
                        $api = array_key_exists(1, $apiPath) ? $apiPath[1] : $api;
369
                    }
370 1
                    foreach ($reflection->getMethods() as $method) {
371 1
                        if ($method->isPublic()) {
372 1
                            $docComments = $method->getDocComment();
373 1
                            preg_match('/@route\ (.*)\n/i', $docComments, $sr);
374 1
                            if (count($sr)) {
375 1
                                list($regex, $default, $params) = $this->extractReflectionParams($sr, $method);
376 1
                                if (strlen($api)) {
377
                                    $regex = str_replace('{__API__}', $api, $regex);
378
                                    $default = str_replace('{__API__}', $api, $default);
379
                                }
380 1
                                $httpMethod = $this->extractReflectionHttpMethod($docComments);
381 1
                                $visible = $this->extractReflectionVisibility($docComments);
382 1
                                $expiration = $this->extractReflectionCacheability($docComments);
383 1
                                $routing[$httpMethod . "#|#" . $regex] = array(
384 1
                                    "class"   => $namespace,
385 1
                                    "method"  => $method->getName(),
386 1
                                    "params"  => $params,
387 1
                                    "default" => $default,
388 1
                                    "visible" => $visible,
389 1
                                    "http"    => $httpMethod,
390 1
                                    "cache"   => $expiration,
391
                                );
392 1
                            }
393 1
                        }
394 1
                    }
395 1
                }
396 1
            }
397
398 1
            return $routing;
399
        }
400
401
        /**
402
         * Método que extrae de la ReflectionClass los datos necesarios para componer los dominios en los templates
403
         *
404
         * @param \ReflectionClass $class
405
         *
406
         * @return Router
407
         * @throws ConfigException
408
         */
409 1
        protected function extractDomain($class)
410
        {
411
            //Calculamos los dominios para las plantillas
412 1
            if ($class->hasConstant("DOMAIN")) {
413 1
                $domain = "@" . $class->getConstant("DOMAIN") . "/";
414 1
                $path = dirname($class->getFileName()) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR;
415 1
                $path = realpath($path) . DIRECTORY_SEPARATOR;
416 1
                $tpl_path = "templates";
417 1
                $public_path = "public";
418 1
                $model_path = "models";
419 1
                if (!preg_match("/ROOT/", $domain)) {
420
                    $tpl_path = ucfirst($tpl_path);
421
                    $public_path = ucfirst($public_path);
422
                    $model_path = ucfirst($model_path);
423
                }
424 1
                if ($class->hasConstant("TPL")) {
425
                    $tpl_path .= DIRECTORY_SEPARATOR . $class->getConstant("TPL");
426
                }
427 1
                $this->domains[$domain] = array(
428 1
                    "template" => $path . $tpl_path,
429 1
                    "model"    => $path . $model_path,
430 1
                    "public"   => $path . $public_path,
431
                );
432 1
            }
433
434 1
            return $this;
435
        }
436
437
        /**
438
         * Método que genera las urls amigables para usar dentro del framework
439
         * @return Router
440
         */
441 1
        public function simpatize()
442
        {
443 1
            $translationFileName = "translations" . DIRECTORY_SEPARATOR . "routes_translations.php";
444 1
            $absoluteTranslationFileName = CACHE_DIR . DIRECTORY_SEPARATOR . $translationFileName;
445 1
            $this->generateSlugs($absoluteTranslationFileName);
446 1
            Config::createDir(CONFIG_DIR);
447 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 148 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...
448
449 1
            return $this;
450
        }
451
452
        /**
453
         * Método que devuelve el slug de un string dado
454
         *
455
         * @param string $text
456
         *
457
         * @return string
458
         */
459 1
        private function slugify($text)
460
        {
461
            // replace non letter or digits by -
462 1
            $text = preg_replace('~[^\\pL\d]+~u', '-', $text);
463
464
            // trim
465 1
            $text = trim($text, '-');
466
467
            // transliterate
468 1
            if (function_exists('iconv')) {
469 1
                $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
470 1
            }
471
472
            // lowercase
473 1
            $text = strtolower($text);
474
475
            // remove unwanted characters
476 1
            $text = preg_replace('~[^-\w]+~', '', $text);
477
478 1
            if (empty($text)) {
479
                return 'n-a';
480
            }
481
482 1
            return $text;
483
        }
484
485
        /**
486
         * Método que devuelve una ruta del framework
487
         *
488
         * @param string $slug
489
         * @param boolean $absolute
490
         * @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...
491
         *
492
         * @return string|null
493
         * @throws RouterException
494
         */
495
        public function getRoute($slug = '', $absolute = FALSE, $params = NULL)
496
        {
497
            if (strlen($slug) === 0) {
498
                return ($absolute) ? Request::getInstance()->getRootUrl() . '/' : '/';
499
            }
500
            if (NULL === $slug || !array_key_exists($slug, $this->slugs)) {
501
                throw new RouterException(_("No existe la ruta especificada"));
502
            }
503
            $url = ($absolute) ? Request::getInstance()->getRootUrl() . $this->slugs[$slug] : $this->slugs[$slug];
504
            if (!empty($params)) foreach ($params as $key => $value) {
505
                $url = str_replace("{" . $key . "}", $value, $url);
506
            } elseif (!empty($this->routing[$this->slugs[$slug]]["default"])) {
507
                $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 172 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...
508
            }
509
510
            return preg_replace('/(GET|POST|PUT|DELETE|ALL)\#\|\#/', '', $url);
511
        }
512
513
        /**
514
         * Método que devuelve las rutas de administración
515
         * @return array
516
         */
517 1
        public function getAdminRoutes()
518
        {
519 1
            $routes = array();
520 1
            foreach ($this->routing as $route => $params) {
521 1
                list($httpMethod, $routePattern) = $this->extractHttpRoute($route);
522 1
                if (preg_match('/^\/admin(\/|$)/', $routePattern)) {
523 1
                    if (preg_match('/^PSFS/', $params["class"])) {
524 1
                        $profile = "superadmin";
525 1
                    } else {
526
                        $profile = "admin";
527
                    }
528 1
                    if (!empty($params["default"]) && preg_match('/(GET|ALL)/i', $httpMethod)) {
529 1
                        $_profile = ($params["visible"]) ? $profile : 'adminhidden';
530 1
                        if(!array_key_exists($_profile, $routes)) {
531 1
                            $routes[$_profile] = array();
532 1
                        }
533 1
                        $routes[$_profile][] = $params["slug"];
534 1
                    }
535 1
                }
536 1
            }
537 1
            if (array_key_exists("superadmin", $routes)) {
538 1
                asort($routes["superadmin"]);
539 1
            }
540 1
            if (array_key_exists("adminhidden", $routes)) {
541 1
                asort($routes["adminhidden"]);
542 1
            }
543 1
            if (array_key_exists('admin', $routes)) {
544
                asort($routes["admin"]);
545
            }
546 1
            return $routes;
547
        }
548
549
        /**
550
         * Método que devuelve le controlador del admin
551
         * @return Admin
552
         */
553
        public function getAdmin()
554
        {
555
            return Admin::getInstance();
556
        }
557
558
        /**
559
         * Método que extrae los dominios
560
         * @return array|null
0 ignored issues
show
Documentation introduced by
Should the return type not be array|string? Also, consider making the array more specific, something like array<String>, or String[].

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.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
561
         */
562
        public function getDomains()
563
        {
564
            return $this->domains;
565
        }
566
567
        /**
568
         * Método que extrae el controller a invocar
569
         *
570
         * @param string $action
571
         *
572
         * @return Object
573
         */
574
        protected function getClassToCall($action)
575
        {
576
            Logger::log('Getting class to call for executing the request action', LOG_DEBUG, $action);
0 ignored issues
show
Documentation introduced by
$action is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
577
            $actionClass = class_exists($action["class"]) ? $action["class"] : "\\" . $action["class"];
578
            $class = (method_exists($actionClass, "getInstance")) ? $actionClass::getInstance() : new $actionClass;
579
            return $class;
580
        }
581
582
        /**
583
         * Método que compara la ruta web con la guardada en la cache
584
         *
585
         * @param $routePattern
586
         * @param $path
587
         *
588
         * @return bool
589
         */
590
        protected function matchRoutePattern($routePattern, $path)
591
        {
592
            $expr = preg_replace('/\{(.*)\}/', '###', $routePattern);
593
            $expr = preg_quote($expr, '/');
594
            $expr = str_replace('###', '(.*)', $expr);
595
            $expr2 = preg_replace('/\(\.\*\)$/', '', $expr);
596
            $matched = preg_match('/^' . $expr . '\/?$/i', $path) || preg_match('/^' . $expr2 . '?$/i', $path);
597
            return $matched;
598
        }
599
600
        /**
601
         * @param $pattern
602
         *
603
         * @return array
604
         */
605 2
        protected function extractHttpRoute($pattern)
606
        {
607 2
            $httpMethod = "ALL";
608 2
            $routePattern = $pattern;
609 2
            if (FALSE !== strstr($pattern, "#|#")) {
610 2
                list($httpMethod, $routePattern) = explode("#|#", $pattern, 2);
611 2
            }
612
613 2
            return array(strtoupper($httpMethod), $routePattern);
614
        }
615
616
        /**
617
         * Método que extrae los parámetros de una función
618
         *
619
         * @param array $sr
620
         * @param \ReflectionMethod $method
621
         *
622
         * @return array
623
         */
624 1
        private function extractReflectionParams($sr, $method)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $sr. 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...
625
        {
626 1
            $regex = $sr[1] ?: $sr[0];
627 1
            $default = '';
628 1
            $params = array();
629 1
            $parameters = $method->getParameters();
630 1
            if (count($parameters) > 0) foreach ($parameters as $param) {
631 1
                if ($param->isOptional() && !is_array($param->getDefaultValue())) {
632 1
                    $params[$param->getName()] = $param->getDefaultValue();
633 1
                    $default = str_replace('{' . $param->getName() . '}', $param->getDefaultValue(), $regex);
634 1
                }
635 1
            } else $default = $regex;
636
637 1
            return array($regex, $default, $params);
638
        }
639
640
        /**
641
         * Método que extrae el método http
642
         *
643
         * @param string $docComments
644
         *
645
         * @return string
646
         */
647 1
        private function extractReflectionHttpMethod($docComments)
648
        {
649 1
            preg_match('/@(GET|POST|PUT|DELETE)\n/i', $docComments, $routeMethod);
650
651 1
            return (count($routeMethod) > 0) ? $routeMethod[1] : "ALL";
652
        }
653
654
        /**
655
         * Método que extrae la visibilidad de una ruta
656
         *
657
         * @param string $docComments
658
         *
659
         * @return bool
660
         */
661 1
        private function extractReflectionVisibility($docComments)
662
        {
663 1
            preg_match('/@visible\ (.*)\n/i', $docComments, $visible);
664 1
            return !(array_key_exists(1, $visible) && preg_match('/false/i', $visible[1]));
665
        }
666
667
        /**
668
         * Método que extrae el parámetro de caché
669
         *
670
         * @param string $docComments
671
         *
672
         * @return bool
673
         */
674 1
        private function extractReflectionCacheability($docComments)
675
        {
676 1
            preg_match('/@cache\ (.*)\n/i', $docComments, $cache);
677
678 1
            return (count($cache) > 0) ? $cache[1] : "0";
679
        }
680
681
        /**
682
         * Método que ejecuta una acción del framework y revisa si lo tenemos cacheado ya o no
683
         *
684
         * @param string $route
685
         * @param array $action
686
         * @param types\Controller $class
687
         * @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...
688
         */
689
        protected function executeCachedRoute($route, $action, $class, $params = NULL)
690
        {
691
            Logger::log('Executing route ' . $route);
692
            $this->session->setSessionKey("__CACHE__", $action);
693
            $cache = Cache::needCache();
694
            $execute = TRUE;
695
            if (FALSE !== $cache && Config::getInstance()->getDebugMode() === FALSE) {
696
                $cacheDataName = $this->cache->getRequestCacheHash();
697
                $cachedData = $this->cache->readFromCache("templates" . DIRECTORY_SEPARATOR . $cacheDataName, $cache, function () {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 131 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...
698
                });
699
                if (NULL !== $cachedData) {
700
                    $headers = $this->cache->readFromCache("templates" . DIRECTORY_SEPARATOR . $cacheDataName . ".headers", $cache, function () {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 145 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...
701
                    }, Cache::JSON);
702
                    Template::getInstance()->renderCache($cachedData, $headers);
703
                    $execute = FALSE;
704
                }
705
            }
706
            if ($execute) {
707
                call_user_func_array(array($class, $action['method']), $params);
708
            }
709
        }
710
711
        /**
712
         * Parse slugs to create translations
713
         *
714
         * @param string $absoluteTranslationFileName
715
         */
716 1
        private function generateSlugs($absoluteTranslationFileName)
717
        {
718 1
            $translations = $this->generateTranslationsFile($absoluteTranslationFileName);
719 1
            foreach ($this->routing as $key => &$info) {
720 1
                if (preg_match('/(ALL|GET)/i', $key)) {
721 1
                    $keyParts = $key;
722 1
                    if (FALSE === strstr("#|#", $key)) {
723 1
                        $keyParts = explode("#|#", $key);
724 1
                        $keyParts = $keyParts[1];
725 1
                    }
726 1
                    $slug = $this->slugify($keyParts);
727 1
                    if (NULL !== $slug && !array_key_exists($slug, $translations)) {
728 1
                        $translations[$slug] = $key;
729 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 136 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...
730 1
                    }
731 1
                    $this->slugs[$slug] = $key;
732 1
                    $info["slug"] = $slug;
733 1
                }
734 1
            }
735 1
        }
736
737
        /**
738
         * Create translation file if not exists
739
         *
740
         * @param string $absoluteTranslationFileName
741
         *
742
         * @return array
743
         */
744 1
        private function generateTranslationsFile($absoluteTranslationFileName)
745
        {
746 1
            $translations = array();
747 1
            if (file_exists($absoluteTranslationFileName)) {
748 1
                include($absoluteTranslationFileName);
749 1
            } else {
750 1
                Cache::getInstance()->storeData($absoluteTranslationFileName, "<?php \$translations = array();\n", Cache::TEXT, TRUE);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 134 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...
751
            }
752
753 1
            return $translations;
754
        }
755
        
756
    }
757