Completed
Push — master ( e69aaa...f09f8b )
by Fran
02:48
created

Router::getDomains()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
c 5
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
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
        public function __construct()
49
        {
50
            $this->finder = new Finder();
51
            $this->cache = Cache::getInstance();
52
            $this->session = Security::getInstance();
53
            $this->init();
54
        }
55
56
        /**
57
         * Inicializador Router
58
         * @throws ConfigException
59
         */
60
        public function init()
61
        {
62
            if (!file_exists(CONFIG_DIR . DIRECTORY_SEPARATOR . "urls.json") || Config::getInstance()->getDebugMode()) {
63
                $this->hydrateRouting();
64
                $this->simpatize();
65
            } else {
66
                list($this->routing, $this->slugs) = $this->cache->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . "urls.json", Cache::JSON, TRUE);
67
                $this->domains = $this->cache->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . "domains.json", Cache::JSON, TRUE);
68
            }
69
        }
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)
79
        {
80
            $template = Template::getInstance()
81
                ->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
                    $e = new \Exception(_('Página no encontrada'), 404);
90
                }
91
92
                return $template->render('error.html.twig', array(
93
                    'exception'  => $e,
94
                    'trace'      => $e->getTraceAsString(),
95
                    'error_page' => TRUE,
96
                ));
97
            }
98
        }
99
100
        /**
101
         * Método que devuelve las rutas
102
         * @return string|null
103
         */
104
        public function getSlugs()
105
        {
106
            return $this->slugs;
107
        }
108
109
        /**
110
         * Método que calcula el objeto a enrutar
111
         *
112
         * @param string $route
113
         *
114
         * @throws \Exception
115
         * @return string HTML
116
         */
117
        public function execute($route)
118
        {
119
            try {
120
                //Check CORS for requests
121
                $this->checkCORS();
122
                // Checks restricted access
123
                $this->checkRestrictedAccess($route);
124
125
                //Search action and execute
126
                return $this->searchAction($route);
127
            } catch (AccessDeniedException $e) {
128
                Logger::getInstance()->debugLog(_('Solicitamos credenciales de acceso a zona restringida'));
129
                if ('login' === Config::getInstance()->get('admin_login')) {
130
                    return $this->redirectLogin($route);
131
                } else {
132
                    return $this->sentAuthHeader();
133
                }
134
            } catch (RouterException $r) {
135
                if (FALSE !== preg_match('/\/$/', $route)) {
136
                    if (preg_match('/admin/', $route)) {
137
                        $default = Config::getInstance()->get('admin_action');
138
                    } else {
139
                        $default = Config::getInstance()->get('home_action');
140
                    }
141
142
                    return $this->execute($this->getRoute($default));
143
                }
144
            } catch (\Exception $e) {
145
                Logger::getInstance()->errorLog($e->getMessage());
146
                throw $e;
147
            }
148
149
            return $this->httpNotFound();
150
        }
151
152
        /**
153
         * Check CROS requests
154
         */
155
        private function checkCORS()
156
        {
157
            $corsEnabled = Config::getInstance()->get('cors.enabled');
158
            $request = Request::getInstance();
159
            if (NULL !== $corsEnabled && null !== $request->getServer('HTTP_REFERER')) {
160
                if($corsEnabled == '*' || preg_match($corsEnabled, $request->getServer('HTTP_REFERER'))) {
161
                    if (!$this->headersSent) {
162
                        header("Access-Control-Allow-Credentials: true");
163
                        header("Access-Control-Allow-Origin: *");
164
                        header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
165
                        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");
166
                        $this->headersSent = true;
167
                    }
168
                    if(Request::getInstance()->getMethod() == 'OPTIONS') {
169
                        header( "HTTP/1.1 200 OK" );
170
                        exit();
171
                    }
172
                }
173
            }
174
        }
175
176
        /**
177
         * Método que busca el componente que ejecuta la ruta
178
         *
179
         * @param string $route
180
         *
181
         * @throws \Exception
182
         */
183
        protected function searchAction($route)
184
        {
185
            //Revisamos si tenemos la ruta registrada
186
            $parts = parse_url($route);
187
            $path = (array_key_exists('path', $parts)) ? $parts['path'] : $route;
188
            $httpRequest = Request::getInstance()->getMethod();
189
            foreach ($this->routing as $pattern => $action) {
190
                list($httpMethod, $routePattern) = $this->extractHttpRoute($pattern);
191
                $matched = $this->matchRoutePattern($routePattern, $path);
192
                if ($matched && ($httpMethod === "ALL" || $httpRequest === $httpMethod)) {
193
                    $get = $this->extractComponents($route, $routePattern);
194
                    /** @var $class \PSFS\base\types\Controller */
195
                    $class = $this->getClassToCall($action);
196
                    try {
197
                        return $this->executeCachedRoute($route, $action, $class, $get);
198
                    } catch (\Exception $e) {
199
                        Logger::getInstance()->debugLog($e->getMessage(), array($e->getFile(), $e->getLine()));
200
                        throw new RouterException($e->getMessage(), 404, $e);
201
                    }
202
                }
203
            }
204
            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
         * Método que redirige a la pantalla web del login
218
         *
219
         * @param string $route
220
         *
221
         * @return string HTML
222
         */
223
        public function redirectLogin($route)
224
        {
225
            return Admin::staticAdminLogon($route);
226
        }
227
228
        /**
229
         * Método que chequea el acceso a una zona restringida
230
         *
231
         * @param string $route
232
         *
233
         * @throws AccessDeniedException
234
         */
235
        protected function checkRestrictedAccess($route)
236
        {
237
            //Chequeamos si entramos en el admin
238
            if (preg_match('/^\/admin/i', $route)
239
                || (!preg_match('/^\/(admin|setup\-admin)/i', $route) && NULL !== Config::getInstance()->get('restricted'))
240
            ) {
241
                if (!preg_match('/^\/admin\/login/i', $route) && !$this->session->checkAdmin()) {
242
                    throw new AccessDeniedException();
243
                }
244
                Logger::getInstance()->debugLog('Acceso autenticado al admin');
245
            }
246
        }
247
248
        /**
249
         * Método que extrae de la url los parámetros REST
250
         *
251
         * @param string $route
252
         *
253
         * @param string $pattern
254
         *
255
         * @return array
256
         */
257
        protected function extractComponents($route, $pattern)
258
        {
259
            $url = parse_url($route);
260
            $_route = explode("/", $url['path']);
261
            $_pattern = explode("/", $pattern);
262
            $get = array();
263
            if (!empty($_pattern)) foreach ($_pattern as $index => $component) {
264
                $_get = array();
265
                preg_match_all('/^\{(.*)\}$/i', $component, $_get);
266
                if (!empty($_get[1]) && isset($_route[$index])) {
267
                    $get[array_pop($_get[1])] = $_route[$index];
268
                }
269
            }
270
271
            return $get;
272
        }
273
274
        /**
275
         * Método que regenera el fichero de rutas
276
         * @throws ConfigException
277
         */
278
        private function hydrateRouting()
279
        {
280
            $base = SOURCE_DIR;
281
            $modules = realpath(CORE_DIR);
282
            $this->routing = $this->inspectDir($base, "PSFS", array());
283
            if (file_exists($modules)) {
284
                $this->routing = $this->inspectDir($modules, "", $this->routing);
285
            }
286
            $this->cache->storeData(CONFIG_DIR . DIRECTORY_SEPARATOR . "domains.json", $this->domains, Cache::JSON, TRUE);
287
            $home = Config::getInstance()->get('home_action');
288
            if (NULL !== $home || $home !== '') {
289
                $home_params = NULL;
290
                foreach ($this->routing as $pattern => $params) {
291
                    list($method, $route) = $this->extractHttpRoute($pattern);
292
                    if (preg_match("/" . preg_quote($route, "/") . "$/i", "/" . $home)) {
293
                        $home_params = $params;
294
                    }
295
                }
296
                if (NULL !== $home_params) {
297
                    $this->routing['/'] = $home_params;
298
                }
299
            }
300
        }
301
302
        /**
303
         * Método que inspecciona los directorios en busca de clases que registren rutas
304
         *
305
         * @param string $origen
306
         * @param string $namespace
307
         * @param array $routing
308
         *
309
         * @return array
310
         * @throws ConfigException
311
         */
312
        private function inspectDir($origen, $namespace = 'PSFS', $routing)
313
        {
314
            $files = $this->finder->files()->in($origen)->path('/(controller|api)/i')->name("*.php");
315
            foreach ($files as $file) {
316
                $filename = str_replace("/", '\\', str_replace($origen, '', $file->getPathname()));
317
                $routing = $this->addRouting($namespace . str_replace('.php', '', $filename), $routing);
318
            }
319
            $this->finder = new Finder();
320
321
            return $routing;
322
        }
323
324
        /**
325
         * Método que añade nuevas rutas al array de referencia
326
         *
327
         * @param string $namespace
328
         * @param array $routing
329
         *
330
         * @return array
331
         * @throws ConfigException
332
         */
333
        private function addRouting($namespace, $routing)
334
        {
335
            if (class_exists($namespace)) {
336
                $reflection = new \ReflectionClass($namespace);
337
                if (FALSE === $reflection->isAbstract() && FALSE === $reflection->isInterface()) {
338
                    $this->extractDomain($reflection);
339
                    $classComments = $reflection->getDocComment();
340
                    preg_match('/@api\ (.*)\n/im', $classComments, $apiPath);
341
                    $api = '';
342
                    if (count($apiPath)) {
343
                        $api = array_key_exists(1, $apiPath) ? $apiPath[1] : $api;
344
                    }
345
                    foreach ($reflection->getMethods() as $method) {
346
                        if ($method->isPublic()) {
347
                            $docComments = $method->getDocComment();
348
                            preg_match('/@route\ (.*)\n/i', $docComments, $sr);
349
                            if (count($sr)) {
350
                                list($regex, $default, $params) = $this->extractReflectionParams($sr, $method);
351
                                if (strlen($api)) {
352
                                    $regex = str_replace('{__API__}', $api, $regex);
353
                                    $default = str_replace('{__API__}', $api, $default);
354
                                }
355
                                $httpMethod = $this->extractReflectionHttpMethod($docComments);
356
                                $visible = $this->extractReflectionVisibility($docComments);
357
                                $expiration = $this->extractReflectionCacheability($docComments);
358
                                $routing[$httpMethod . "#|#" . $regex] = array(
359
                                    "class"   => $namespace,
360
                                    "method"  => $method->getName(),
361
                                    "params"  => $params,
362
                                    "default" => $default,
363
                                    "visible" => $visible,
364
                                    "http"    => $httpMethod,
365
                                    "cache"   => $expiration,
366
                                );
367
                            }
368
                        }
369
                    }
370
                }
371
            }
372
373
            return $routing;
374
        }
375
376
        /**
377
         * Método que extrae de la ReflectionClass los datos necesarios para componer los dominios en los templates
378
         *
379
         * @param \ReflectionClass $class
380
         *
381
         * @return Router
382
         * @throws ConfigException
383
         */
384
        protected function extractDomain($class)
385
        {
386
            //Calculamos los dominios para las plantillas
387
            if ($class->hasConstant("DOMAIN")) {
388
                $domain = "@" . $class->getConstant("DOMAIN") . "/";
389
                $path = dirname($class->getFileName()) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR;
390
                $path = realpath($path) . DIRECTORY_SEPARATOR;
391
                $tpl_path = "templates";
392
                $public_path = "public";
393
                $model_path = "models";
394
                if (!preg_match("/ROOT/", $domain)) {
395
                    $tpl_path = ucfirst($tpl_path);
396
                    $public_path = ucfirst($public_path);
397
                    $model_path = ucfirst($model_path);
398
                }
399
                if ($class->hasConstant("TPL")) {
400
                    $tpl_path .= DIRECTORY_SEPARATOR . $class->getConstant("TPL");
401
                }
402
                $this->domains[$domain] = array(
403
                    "template" => $path . $tpl_path,
404
                    "model"    => $path . $model_path,
405
                    "public"   => $path . $public_path,
406
                );
407
            }
408
409
            return $this;
410
        }
411
412
        /**
413
         * Método que genera las urls amigables para usar dentro del framework
414
         * @return Router
415
         */
416
        private function simpatize()
417
        {
418
            $translationFileName = "translations" . DIRECTORY_SEPARATOR . "routes_translations.php";
419
            $absoluteTranslationFileName = CACHE_DIR . DIRECTORY_SEPARATOR . $translationFileName;
420
            $this->generateSlugs($absoluteTranslationFileName);
421
            Config::createDir(CONFIG_DIR);
422
            Cache::getInstance()->storeData(CONFIG_DIR . DIRECTORY_SEPARATOR . "urls.json", array($this->routing, $this->slugs), Cache::JSON, TRUE);
423
424
            return $this;
425
        }
426
427
        /**
428
         * Método que devuelve el slug de un string dado
429
         *
430
         * @param string $text
431
         *
432
         * @return string
433
         */
434
        private function slugify($text)
435
        {
436
            // replace non letter or digits by -
437
            $text = preg_replace('~[^\\pL\d]+~u', '-', $text);
438
439
            // trim
440
            $text = trim($text, '-');
441
442
            // transliterate
443
            if (function_exists('iconv')) {
444
                $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
445
            }
446
447
            // lowercase
448
            $text = strtolower($text);
449
450
            // remove unwanted characters
451
            $text = preg_replace('~[^-\w]+~', '', $text);
452
453
            if (empty($text)) {
454
                return 'n-a';
455
            }
456
457
            return $text;
458
        }
459
460
        /**
461
         * Método que devuelve una ruta del framework
462
         *
463
         * @param string $slug
464
         * @param boolean $absolute
465
         * @param array $params
466
         *
467
         * @return string|null
468
         * @throws RouterException
469
         */
470
        public function getRoute($slug = '', $absolute = FALSE, $params = NULL)
471
        {
472
            if (strlen($slug) === 0) {
473
                return ($absolute) ? Request::getInstance()->getRootUrl() . '/' : '/';
474
            }
475
            if (NULL === $slug || !array_key_exists($slug, $this->slugs)) {
476
                throw new RouterException(_("No existe la ruta especificada"));
477
            }
478
            $url = ($absolute) ? Request::getInstance()->getRootUrl() . $this->slugs[$slug] : $this->slugs[$slug];
479
            if (!empty($params)) foreach ($params as $key => $value) {
480
                $url = str_replace("{" . $key . "}", $value, $url);
481
            } elseif (!empty($this->routing[$this->slugs[$slug]]["default"])) {
482
                $url = ($absolute) ? Request::getInstance()->getRootUrl() . $this->routing[$this->slugs[$slug]]["default"] : $this->routing[$this->slugs[$slug]]["default"];
483
            }
484
485
            return preg_replace('/(GET|POST|PUT|DELETE|ALL)\#\|\#/', '', $url);
486
        }
487
488
        /**
489
         * Método que devuelve las rutas de administración
490
         * @return array
491
         */
492
        public function getAdminRoutes()
493
        {
494
            $routes = array();
495
            foreach ($this->routing as $route => $params) {
496
                list($httpMethod, $routePattern) = $this->extractHttpRoute($route);
497
                if (preg_match('/^\/admin(\/|$)/', $routePattern)) {
498
                    if (preg_match('/^PSFS/', $params["class"])) {
499
                        $profile = "superadmin";
500
                    } else {
501
                        $profile = "admin";
502
                    }
503
                    if (!empty($params["default"]) && preg_match('/(GET|ALL)/i', $httpMethod)) {
504
                        $_profile = ($params["visible"]) ? $profile : 'adminhidden';
505
                        if(!array_key_exists($_profile, $routes)) {
506
                            $routes[$_profile] = array();
507
                        }
508
                        $routes[$_profile][] = $params["slug"];
509
                    }
510
                }
511
            }
512
            if (array_key_exists("superadmin", $routes)) {
513
                asort($routes["superadmin"]);
514
            }
515
            if (array_key_exists("adminhidden", $routes)) {
516
                asort($routes["adminhidden"]);
517
            }
518
            if (array_key_exists('admin', $routes)) {
519
                asort($routes["admin"]);
520
            }
521
522
            return $routes;
523
        }
524
525
        /**
526
         * Método que devuelve le controlador del admin
527
         * @return Admin
528
         */
529
        public function getAdmin()
530
        {
531
            return Admin::getInstance();
532
        }
533
534
        /**
535
         * Método que extrae los dominios
536
         * @return array|null
537
         */
538
        public function getDomains()
539
        {
540
            return $this->domains;
541
        }
542
543
        /**
544
         * Método que extrae el controller a invocar
545
         *
546
         * @param string $action
547
         *
548
         * @return Object
549
         */
550
        protected function getClassToCall($action)
551
        {
552
            $class = (method_exists($action["class"], "getInstance")) ? $action["class"]::getInstance() : new $action["class"];
553
            if (NULL !== $class && method_exists($class, "init")) {
554
                $class->init();
555
            }
556
557
            return $class;
558
        }
559
560
        /**
561
         * Método que compara la ruta web con la guardada en la cache
562
         *
563
         * @param $routePattern
564
         * @param $path
565
         *
566
         * @return bool
567
         */
568
        protected function matchRoutePattern($routePattern, $path)
569
        {
570
            $expr = preg_replace('/\{(.*)\}/', '###', $routePattern);
571
            $expr = preg_quote($expr, '/');
572
            $expr = str_replace('###', '(.*)', $expr);
573
            $expr2 = preg_replace('/\(\.\*\)$/', '', $expr);
574
            $matched = preg_match('/^' . $expr . '\/?$/i', $path) || preg_match('/^' . $expr2 . '?$/i', $path);
575
576
            return $matched;
577
        }
578
579
        /**
580
         * @param $pattern
581
         *
582
         * @return array
583
         */
584
        protected function extractHttpRoute($pattern)
585
        {
586
            $httpMethod = "ALL";
587
            $routePattern = $pattern;
588
            if (FALSE !== strstr($pattern, "#|#")) {
589
                list($httpMethod, $routePattern) = explode("#|#", $pattern, 2);
590
            }
591
592
            return array($httpMethod, $routePattern);
593
        }
594
595
        /**
596
         * Método que extrae los parámetros de una función
597
         *
598
         * @param array $sr
599
         * @param \ReflectionMethod $method
600
         *
601
         * @return array
602
         */
603
        private function extractReflectionParams($sr, $method)
604
        {
605
            $regex = $sr[1] ?: $sr[0];
606
            $default = '';
607
            $params = array();
608
            $parameters = $method->getParameters();
609
            if (count($parameters) > 0) foreach ($parameters as $param) {
610
                if ($param->isOptional() && !is_array($param->getDefaultValue())) {
611
                    $params[$param->getName()] = $param->getDefaultValue();
612
                    $default = str_replace('{' . $param->getName() . '}', $param->getDefaultValue(), $regex);
613
                }
614
            } else $default = $regex;
615
616
            return array($regex, $default, $params);
617
        }
618
619
        /**
620
         * Método que extrae el método http
621
         *
622
         * @param string $docComments
623
         *
624
         * @return string
625
         */
626
        private function extractReflectionHttpMethod($docComments)
627
        {
628
            preg_match('/@(GET|POST|PUT|DELETE)\n/i', $docComments, $routeMethod);
629
630
            return (count($routeMethod) > 0) ? $routeMethod[1] : "ALL";
631
        }
632
633
        /**
634
         * Método que extrae la visibilidad de una ruta
635
         *
636
         * @param string $docComments
637
         *
638
         * @return bool
639
         */
640
        private function extractReflectionVisibility($docComments)
641
        {
642
            preg_match('/@visible\ (.*)\n/i', $docComments, $visible);
643
644
            return (!empty($visible) && isset($visible[1]) && $visible[1] == 'false') ? FALSE : TRUE;
645
        }
646
647
        /**
648
         * Método que extrae el parámetro de caché
649
         *
650
         * @param string $docComments
651
         *
652
         * @return bool
653
         */
654
        private function extractReflectionCacheability($docComments)
655
        {
656
            preg_match('/@cache\ (.*)\n/i', $docComments, $cache);
657
658
            return (count($cache) > 0) ? $cache[1] : "0";
659
        }
660
661
        /**
662
         * Método que ejecuta una acción del framework y revisa si lo tenemos cacheado ya o no
663
         *
664
         * @param string $route
665
         * @param array $action
666
         * @param types\Controller $class
667
         * @param array $params
668
         */
669
        protected function executeCachedRoute($route, $action, $class, $params = NULL)
670
        {
671
            Logger::getInstance()->debugLog(_('Ruta resuelta para ') . $route);
672
            $this->session->setSessionKey("__CACHE__", $action);
673
            $cache = Cache::needCache();
674
            $execute = TRUE;
675
            if (FALSE !== $cache && Config::getInstance()->getDebugMode() === FALSE) {
676
                $cacheDataName = $this->cache->getRequestCacheHash();
677
                $cachedData = $this->cache->readFromCache("templates" . DIRECTORY_SEPARATOR . $cacheDataName, $cache, function () {
678
                });
679
                if (NULL !== $cachedData) {
680
                    $headers = $this->cache->readFromCache("templates" . DIRECTORY_SEPARATOR . $cacheDataName . ".headers", $cache, function () {
681
                    }, Cache::JSON);
682
                    Template::getInstance()->renderCache($cachedData, $headers);
683
                    $execute = FALSE;
684
                }
685
            }
686
            if ($execute) {
687
                call_user_func_array(array($class, $action['method']), $params);
688
            }
689
        }
690
691
        /**
692
         * Parse slugs to create translations
693
         *
694
         * @param string $absoluteTranslationFileName
695
         */
696
        private function generateSlugs($absoluteTranslationFileName)
697
        {
698
            $translations = $this->generateTranslationsFile($absoluteTranslationFileName);
699
            foreach ($this->routing as $key => &$info) {
700
                if (preg_match('/(ALL|GET)/i', $key)) {
701
                    $keyParts = $key;
702
                    if (FALSE === strstr("#|#", $key)) {
703
                        $keyParts = explode("#|#", $key);
704
                        $keyParts = $keyParts[1];
705
                    }
706
                    $slug = $this->slugify($keyParts);
707
                    if (NULL !== $slug && !array_key_exists($slug, $translations)) {
708
                        $translations[$slug] = $key;
709
                        file_put_contents($absoluteTranslationFileName, "\$translations[\"{$slug}\"] = _(\"{$slug}\");\n", FILE_APPEND);
710
                    }
711
                    $this->slugs[$slug] = $key;
712
                    $info["slug"] = $slug;
713
                }
714
            }
715
        }
716
717
        /**
718
         * Create translation file if not exists
719
         *
720
         * @param string $absoluteTranslationFileName
721
         *
722
         * @return array
723
         */
724
        private function generateTranslationsFile($absoluteTranslationFileName)
725
        {
726
            $translations = array();
727
            if (file_exists($absoluteTranslationFileName)) {
728
                include($absoluteTranslationFileName);
729
            } else {
730
                Cache::getInstance()->storeData($absoluteTranslationFileName, "<?php \$translations = array();\n", Cache::TEXT, TRUE);
731
            }
732
733
            return $translations;
734
        }
735
    }
736