Completed
Push — master ( 8a02a1...c877ec )
by Fran
04:56 queued 14s
created

Router::extractReflectionVisibility()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 3
b 0
f 0
nc 2
nop 1
dl 0
loc 5
rs 9.4285
ccs 3
cts 3
cp 1
crap 2
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 1
            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 146 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
            $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 129 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::log(_('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::log($e->getMessage(), LOG_ERR);
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 246 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
    {
188
        $pattern_sep = count(explode('/', $routePattern));
189
        if (preg_match('/\/$/', $routePattern)) {
190
            $pattern_sep--;
191
        }
192
        $path_sep = count(explode('/', $path));
193
        if (preg_match('/\/$/', $path)) {
194
            $path_sep--;
195
        }
196
        return abs($pattern_sep - $path_sep) < 1;
197
    }
198
199
    /**
200
     * Método que busca el componente que ejecuta la ruta
201
     *
202
     * @param string $route
203
     *
204
     * @throws \Exception
205
     */
206
    protected function searchAction($route)
207
    {
208
        Logger::log('Searching action to execute');
209
        //Revisamos si tenemos la ruta registrada
210
        $parts = parse_url($route);
211
        $path = (array_key_exists('path', $parts)) ? $parts['path'] : $route;
212
        $httpRequest = Request::getInstance()->getMethod();
213
        foreach ($this->routing as $pattern => $action) {
214
            list($httpMethod, $routePattern) = $this->extractHttpRoute($pattern);
215
            $matched = $this->matchRoutePattern($routePattern, $path);
216
            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 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...
217
                $get = $this->extractComponents($route, $routePattern);
218
                /** @var $class \PSFS\base\types\Controller */
219
                $class = $this->getClassToCall($action);
220
                try {
221
                    return $this->executeCachedRoute($route, $action, $class, $get);
222
                } catch (\Exception $e) {
223
                    Logger::log($e->getMessage(), LOG_ERR);
224
                    throw new RouterException($e->getMessage(), 404, $e);
225
                }
226
            }
227
        }
228
        throw new RouterException(_("Ruta no encontrada"));
229
    }
230
231
    /**
232
     * Método que manda las cabeceras de autenticación
233
     * @return string HTML
234
     */
235
    protected function sentAuthHeader()
236
    {
237
        return AdminServices::getInstance()->setAdminHeaders();
238
    }
239
240
    /**
241
     * Método que redirige a la pantalla web del login
242
     *
243
     * @param string $route
244
     *
245
     * @return string HTML
246
     */
247
    public function redirectLogin($route)
248
    {
249
        return Admin::staticAdminLogon($route);
250
    }
251
252
    /**
253
     * Método que chequea el acceso a una zona restringida
254
     *
255
     * @param string $route
256
     *
257
     * @throws AccessDeniedException
258
     */
259
    protected function checkRestrictedAccess($route)
260
    {
261
        Logger::log('Checking admin zone');
262
        //Chequeamos si entramos en el admin
263
        if (!Config::getInstance()->checkTryToSaveConfig()
264
            || (!preg_match('/^\/(admin|setup\-admin)/i', $route) && NULL !== Config::getInstance()->get('restricted'))
265
        ) {
266
            if (!$this->session->checkAdmin()) {
267
                throw new AccessDeniedException();
268
            }
269
            Logger::log('Admin access granted');
270
        }
271
    }
272
273
    /**
274
     * Método que extrae de la url los parámetros REST
275
     *
276
     * @param string $route
277
     *
278
     * @param string $pattern
279
     *
280
     * @return array
281
     */
282
    protected function extractComponents($route, $pattern)
283
    {
284
        Logger::log('Extracting parts for the request to execute');
285
        $url = parse_url($route);
286
        $_route = explode("/", $url['path']);
287
        $_pattern = explode("/", $pattern);
288
        $get = array();
289
        if (!empty($_pattern)) foreach ($_pattern as $index => $component) {
290
            $_get = array();
291
            preg_match_all('/^\{(.*)\}$/i', $component, $_get);
292
            if (!empty($_get[1]) && isset($_route[$index])) {
293
                $get[array_pop($_get[1])] = $_route[$index];
294
            }
295
        }
296
297
        return $get;
298
    }
299
300
    /**
301
     * Método que regenera el fichero de rutas
302
     * @throws ConfigException
303
     */
304 1
    public function hydrateRouting()
305
    {
306 1
        $base = SOURCE_DIR;
307 1
        $modules = realpath(CORE_DIR);
308 1
        $this->routing = $this->inspectDir($base, "PSFS", array());
309 1
        if (file_exists($modules)) {
310
            $this->routing = $this->inspectDir($modules, "", $this->routing);
311
        }
312 1
        $this->cache->storeData(CONFIG_DIR . DIRECTORY_SEPARATOR . "domains.json", $this->domains, Cache::JSON, TRUE);
313 1
        $home = Config::getInstance()->get('home_action');
314 1
        if (NULL !== $home || $home !== '') {
315 1
            $home_params = NULL;
316 1
            foreach ($this->routing as $pattern => $params) {
317 1
                list($method, $route) = $this->extractHttpRoute($pattern);
318 1
                if (preg_match("/" . preg_quote($route, "/") . "$/i", "/" . $home)) {
319
                    $home_params = $params;
320
                }
321 1
            }
322 1
            if (NULL !== $home_params) {
323
                $this->routing['/'] = $home_params;
324
            }
325 1
        }
326 1
    }
327
328
    /**
329
     * Método que inspecciona los directorios en busca de clases que registren rutas
330
     *
331
     * @param string $origen
332
     * @param string $namespace
333
     * @param array $routing
334
     *
335
     * @return array
336
     * @throws ConfigException
337
     */
338 1
    private function inspectDir($origen, $namespace = 'PSFS', $routing)
339
    {
340 1
        $files = $this->finder->files()->in($origen)->path('/(controller|api)/i')->name("*.php");
341 1
        foreach ($files as $file) {
342 1
            $filename = str_replace("/", '\\', str_replace($origen, '', $file->getPathname()));
343 1
            $routing = $this->addRouting($namespace . str_replace('.php', '', $filename), $routing);
344 1
        }
345 1
        $this->finder = new Finder();
346
347 1
        return $routing;
348
    }
349
350
    /**
351
     * Método que añade nuevas rutas al array de referencia
352
     *
353
     * @param string $namespace
354
     * @param array $routing
355
     *
356
     * @return array
357
     * @throws ConfigException
358
     */
359 1
    private function addRouting($namespace, $routing)
360
    {
361 1
        if (class_exists($namespace)) {
362 1
            $reflection = new \ReflectionClass($namespace);
363 1
            if (FALSE === $reflection->isAbstract() && FALSE === $reflection->isInterface()) {
364 1
                $this->extractDomain($reflection);
365 1
                $classComments = $reflection->getDocComment();
366 1
                preg_match('/@api\ (.*)\n/im', $classComments, $apiPath);
367 1
                $api = '';
368 1
                if (count($apiPath)) {
369
                    $api = array_key_exists(1, $apiPath) ? $apiPath[1] : $api;
370
                }
371 1
                foreach ($reflection->getMethods() as $method) {
372 1
                    if ($method->isPublic()) {
373 1
                        $docComments = $method->getDocComment();
374 1
                        preg_match('/@route\ (.*)\n/i', $docComments, $sr);
375 1
                        if (count($sr)) {
376 1
                            list($regex, $default, $params) = $this->extractReflectionParams($sr, $method);
377 1
                            if (strlen($api)) {
378
                                $regex = str_replace('{__API__}', $api, $regex);
379
                                $default = str_replace('{__API__}', $api, $default);
380
                            }
381 1
                            $httpMethod = $this->extractReflectionHttpMethod($docComments);
382 1
                            $visible = $this->extractReflectionVisibility($docComments);
383 1
                            $expiration = $this->extractReflectionCacheability($docComments);
384 1
                            $routing[$httpMethod . "#|#" . $regex] = array(
385 1
                                "class" => $namespace,
386 1
                                "method" => $method->getName(),
387 1
                                "params" => $params,
388 1
                                "default" => $default,
389 1
                                "visible" => $visible,
390 1
                                "http" => $httpMethod,
391 1
                                "cache" => $expiration,
392
                            );
393 1
                        }
394 1
                    }
395 1
                }
396 1
            }
397 1
        }
398
399 1
        return $routing;
400
    }
401
402
    /**
403
     * Método que extrae de la ReflectionClass los datos necesarios para componer los dominios en los templates
404
     *
405
     * @param \ReflectionClass $class
406
     *
407
     * @return Router
408
     * @throws ConfigException
409
     */
410 1
    protected function extractDomain(\ReflectionClass $class)
411
    {
412
        //Calculamos los dominios para las plantillas
413 1
        if ($class->hasConstant("DOMAIN")) {
414 1
            $domain = "@" . $class->getConstant("DOMAIN") . "/";
415 1
            $path = dirname($class->getFileName()) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR;
416 1
            $path = realpath($path) . DIRECTORY_SEPARATOR;
417 1
            $tpl_path = "templates";
418 1
            $public_path = "public";
419 1
            $model_path = "models";
420 1
            if (!preg_match("/ROOT/", $domain)) {
421
                $tpl_path = ucfirst($tpl_path);
422
                $public_path = ucfirst($public_path);
423
                $model_path = ucfirst($model_path);
424
            }
425 1
            if ($class->hasConstant("TPL")) {
426
                $tpl_path .= DIRECTORY_SEPARATOR . $class->getConstant("TPL");
427
            }
428 1
            $this->domains[$domain] = array(
429 1
                "template" => $path . $tpl_path,
430 1
                "model" => $path . $model_path,
431 1
                "public" => $path . $public_path,
432
            );
433 1
        }
434
435 1
        return $this;
436
    }
437
438
    /**
439
     * Método que genera las urls amigables para usar dentro del framework
440
     * @return Router
441
     */
442 1
    public function simpatize()
443
    {
444 1
        $translationFileName = "translations" . DIRECTORY_SEPARATOR . "routes_translations.php";
445 1
        $absoluteTranslationFileName = CACHE_DIR . DIRECTORY_SEPARATOR . $translationFileName;
446 1
        $this->generateSlugs($absoluteTranslationFileName);
447 1
        Config::createDir(CONFIG_DIR);
448 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...
449
450 1
        return $this;
451
    }
452
453
    /**
454
     * Método que devuelve el slug de un string dado
455
     *
456
     * @param string $text
457
     *
458
     * @return string
459
     */
460 1
    private function slugify($text)
461
    {
462
        // replace non letter or digits by -
463 1
        $text = preg_replace('~[^\\pL\d]+~u', '-', $text);
464
465
        // trim
466 1
        $text = trim($text, '-');
467
468
        // transliterate
469 1
        if (function_exists('iconv')) {
470 1
            $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
471 1
        }
472
473
        // lowercase
474 1
        $text = strtolower($text);
475
476
        // remove unwanted characters
477 1
        $text = preg_replace('~[^-\w]+~', '', $text);
478
479 1
        if (empty($text)) {
480
            return 'n-a';
481
        }
482
483 1
        return $text;
484
    }
485
486
    /**
487
     * Método que devuelve una ruta del framework
488
     *
489
     * @param string $slug
490
     * @param boolean $absolute
491
     * @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...
492
     *
493
     * @return string|null
494
     * @throws RouterException
495
     */
496
    public function getRoute($slug = '', $absolute = FALSE, $params = NULL)
497
    {
498
        if (strlen($slug) === 0) {
499
            return ($absolute) ? Request::getInstance()->getRootUrl() . '/' : '/';
500
        }
501
        if (NULL === $slug || !array_key_exists($slug, $this->slugs)) {
502
            throw new RouterException(_("No existe la ruta especificada"));
503
        }
504
        $url = ($absolute) ? Request::getInstance()->getRootUrl() . $this->slugs[$slug] : $this->slugs[$slug];
505
        if (!empty($params)) foreach ($params as $key => $value) {
506
            $url = str_replace("{" . $key . "}", $value, $url);
507
        } elseif (!empty($this->routing[$this->slugs[$slug]]["default"])) {
508
            $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...
509
        }
510
511
        return preg_replace('/(GET|POST|PUT|DELETE|ALL)\#\|\#/', '', $url);
512
    }
513
514
    /**
515
     * Método que devuelve las rutas de administración
516
     * @return array
517
     */
518 1
    public function getAdminRoutes()
519
    {
520 1
        $routes = array();
521 1
        foreach ($this->routing as $route => $params) {
522 1
            list($httpMethod, $routePattern) = $this->extractHttpRoute($route);
523 1
            if (preg_match('/^\/admin(\/|$)/', $routePattern)) {
524 1
                if (preg_match('/^PSFS/', $params["class"])) {
525 1
                    $profile = "superadmin";
526 1
                } else {
527
                    $profile = "admin";
528
                }
529 1
                if (!empty($params["default"]) && preg_match('/(GET|ALL)/i', $httpMethod)) {
530 1
                    $_profile = ($params["visible"]) ? $profile : 'adminhidden';
531 1
                    if (!array_key_exists($_profile, $routes)) {
532 1
                        $routes[$_profile] = array();
533 1
                    }
534 1
                    $routes[$_profile][] = $params["slug"];
535 1
                }
536 1
            }
537 1
        }
538 1
        if (array_key_exists("superadmin", $routes)) {
539 1
            asort($routes["superadmin"]);
540 1
        }
541 1
        if (array_key_exists("adminhidden", $routes)) {
542 1
            asort($routes["adminhidden"]);
543 1
        }
544 1
        if (array_key_exists('admin', $routes)) {
545
            asort($routes["admin"]);
546
        }
547 1
        return $routes;
548
    }
549
550
    /**
551
     * Método que devuelve le controlador del admin
552
     * @return Admin
553
     */
554
    public function getAdmin()
555
    {
556
        return Admin::getInstance();
557
    }
558
559
    /**
560
     * Método que extrae los dominios
561
     * @return array|null
0 ignored issues
show
Documentation introduced by
Should the return type not be array|string|null? 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...
562
     */
563
    public function getDomains()
564
    {
565
        return $this->domains;
566
    }
567
568
    /**
569
     * Método que extrae el controller a invocar
570
     *
571
     * @param string $action
572
     *
573
     * @return Object
574
     */
575
    protected function getClassToCall($action)
576
    {
577
        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...
578
        $actionClass = class_exists($action["class"]) ? $action["class"] : "\\" . $action["class"];
579
        $class = (method_exists($actionClass, "getInstance")) ? $actionClass::getInstance() : new $actionClass;
580
        return $class;
581
    }
582
583
    /**
584
     * Método que compara la ruta web con la guardada en la cache
585
     *
586
     * @param $routePattern
587
     * @param $path
588
     *
589
     * @return bool
590
     */
591
    protected function matchRoutePattern($routePattern, $path)
592
    {
593
        $expr = preg_replace('/\{(.*)\}/', '###', $routePattern);
594
        $expr = preg_quote($expr, '/');
595
        $expr = str_replace('###', '(.*)', $expr);
596
        $expr2 = preg_replace('/\(\.\*\)$/', '', $expr);
597
        $matched = preg_match('/^' . $expr . '\/?$/i', $path) || preg_match('/^' . $expr2 . '?$/i', $path);
598
        return $matched;
599
    }
600
601
    /**
602
     * @param $pattern
603
     *
604
     * @return array
605
     */
606 2
    protected function extractHttpRoute($pattern)
607
    {
608 2
        $httpMethod = "ALL";
609 2
        $routePattern = $pattern;
610 2
        if (FALSE !== strstr($pattern, "#|#")) {
611 2
            list($httpMethod, $routePattern) = explode("#|#", $pattern, 2);
612 2
        }
613
614 2
        return array(strtoupper($httpMethod), $routePattern);
615
    }
616
617
    /**
618
     * Método que extrae los parámetros de una función
619
     *
620
     * @param array $sr
621
     * @param \ReflectionMethod $method
622
     *
623
     * @return array
624
     */
625 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...
626
    {
627 1
        $regex = $sr[1] ?: $sr[0];
628 1
        $default = '';
629 1
        $params = array();
630 1
        $parameters = $method->getParameters();
631 1
        if (count($parameters) > 0) foreach ($parameters as $param) {
632 1
            if ($param->isOptional() && !is_array($param->getDefaultValue())) {
633 1
                $params[$param->getName()] = $param->getDefaultValue();
634 1
                $default = str_replace('{' . $param->getName() . '}', $param->getDefaultValue(), $regex);
635 1
            }
636 1
        } else $default = $regex;
637
638 1
        return array($regex, $default, $params);
639
    }
640
641
    /**
642
     * Método que extrae el método http
643
     *
644
     * @param string $docComments
645
     *
646
     * @return string
647
     */
648 1
    private function extractReflectionHttpMethod($docComments)
649
    {
650 1
        preg_match('/@(GET|POST|PUT|DELETE)\n/i', $docComments, $routeMethod);
651
652 1
        return (count($routeMethod) > 0) ? $routeMethod[1] : "ALL";
653
    }
654
655
    /**
656
     * Método que extrae la visibilidad de una ruta
657
     *
658
     * @param string $docComments
659
     *
660
     * @return bool
661
     */
662 1
    private function extractReflectionVisibility($docComments)
663
    {
664 1
        preg_match('/@visible\ (.*)\n/i', $docComments, $visible);
665 1
        return !(array_key_exists(1, $visible) && preg_match('/false/i', $visible[1]));
666
    }
667
668
    /**
669
     * Método que extrae el parámetro de caché
670
     *
671
     * @param string $docComments
672
     *
673
     * @return bool
674
     */
675 1
    private function extractReflectionCacheability($docComments)
676
    {
677 1
        preg_match('/@cache\ (.*)\n/i', $docComments, $cache);
678
679 1
        return (count($cache) > 0) ? $cache[1] : "0";
680
    }
681
682
    /**
683
     * Método que ejecuta una acción del framework y revisa si lo tenemos cacheado ya o no
684
     *
685
     * @param string $route
686
     * @param array $action
687
     * @param types\Controller $class
688
     * @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...
689
     */
690
    protected function executeCachedRoute($route, $action, $class, $params = NULL)
691
    {
692
        Logger::log('Executing route ' . $route);
693
        $this->session->setSessionKey("__CACHE__", $action);
694
        $cache = Cache::needCache();
695
        $execute = TRUE;
696
        if (FALSE !== $cache && Config::getInstance()->getDebugMode() === FALSE) {
697
            $cacheDataName = $this->cache->getRequestCacheHash();
698
            $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 127 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...
699
            });
700
            if (NULL !== $cachedData) {
701
                $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 141 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...
702
                }, Cache::JSON);
703
                Template::getInstance()->renderCache($cachedData, $headers);
704
                $execute = FALSE;
705
            }
706
        }
707
        if ($execute) {
708
            call_user_func_array(array($class, $action['method']), $params);
709
        }
710
    }
711
712
    /**
713
     * Parse slugs to create translations
714
     *
715
     * @param string $absoluteTranslationFileName
716
     */
717 1
    private function generateSlugs($absoluteTranslationFileName)
718
    {
719 1
        $translations = $this->generateTranslationsFile($absoluteTranslationFileName);
720 1
        foreach ($this->routing as $key => &$info) {
721 1
            if (preg_match('/(ALL|GET)/i', $key)) {
722 1
                $keyParts = $key;
723 1
                if (FALSE === strstr("#|#", $key)) {
724 1
                    $keyParts = explode("#|#", $key);
725 1
                    $keyParts = $keyParts[1];
726 1
                }
727 1
                $slug = $this->slugify($keyParts);
728 1
                if (NULL !== $slug && !array_key_exists($slug, $translations)) {
729 1
                    $translations[$slug] = $key;
730 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 132 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...
731 1
                }
732 1
                $this->slugs[$slug] = $key;
733 1
                $info["slug"] = $slug;
734 1
            }
735 1
        }
736 1
    }
737
738
    /**
739
     * Create translation file if not exists
740
     *
741
     * @param string $absoluteTranslationFileName
742
     *
743
     * @return array
744
     */
745 1
    private function generateTranslationsFile($absoluteTranslationFileName)
746
    {
747 1
        $translations = array();
748 1
        if (file_exists($absoluteTranslationFileName)) {
749
            include($absoluteTranslationFileName);
750
        } else {
751 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 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...
752
        }
753
754 1
        return $translations;
755
    }
756
757
}
758