Passed
Push — master ( 74847c...ad33a7 )
by Fran
03:09
created

Template::loadDomains()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 0
dl 0
loc 9
ccs 8
cts 8
cp 1
crap 3
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
namespace PSFS\base;
4
5
6
use PSFS\base\config\Config;
7
use PSFS\base\extension\AssetsTokenParser;
8
use PSFS\base\extension\TemplateFunctions;
9
use PSFS\base\types\helpers\ResponseHelper;
10
use PSFS\base\types\helpers\SecurityHelper;
11
use PSFS\base\types\helpers\TemplateHelper;
12
use PSFS\base\types\SingletonTrait;
13
use PSFS\Dispatcher;
14
15
16
class Template
17
{
18
    use SingletonTrait;
19
    const STATUS_OK = 'HTTP/1.0 200 OK';
20
    /**
21
     * @var \Twig_Environment tpl
22
     */
23
    protected $tpl;
24
    protected $filters = array();
25
26
    protected $debug = false;
27
    protected $public_zone = true;
28
    private $status_code = Template::STATUS_OK;
29
30
    /**
31
     * @var \PSFS\base\Cache $cache
32
     */
33
    protected $cache;
34
35
    /**
36
     * Constructor por defecto
37
     */
38 1
    public function __construct()
39
    {
40 1
        $this->setup();
41 1
        $this->addTemplateFunctions();
42 1
        $this->addTemplateTokens();
43 1
        $this->optimizeTemplates();
44 1
    }
45
46
    /**
47
     * Método que devuelve el loader del Template
48
     * @return \Twig_LoaderInterface
49
     */
50
    public function getLoader()
51
    {
52
        return $this->tpl->getLoader();
53
    }
54
55
    /**
56
     * Método que activa la zona pública
57
     * @param bool $public
58
     *
59
     * @return Template
60
     */
61
    public function setPublicZone($public = true)
62
    {
63
        $this->public_zone = $public;
64
        return $this;
65
    }
66
67
    /**
68
     * Método que establece un header de http status code
69
     * @param string $status
70
     *
71
     * @return Template
72
     */
73
    public function setStatus($status = null)
74
    {
75
        switch ($status) {
76
            //TODO implement all status codes
77
            case '500':
78
                $this->status_code = "HTTP/1.0 500 Internal Server Error";
79
                break;
80
            case '404':
81
                $this->status_code = "HTTP/1.0 404 Not Found";
82
                break;
83
            case '403':
84
                $this->status_code = "HTTP/1.0 403 Forbidden";
85
                break;
86
            case '402':
87
                $this->status_code = "HTTP/1.0 402 Payment Required";
88
                break;
89
            case '401':
90
                $this->status_code = "HTTP/1.0 401 Unauthorized";
91
                break;
92
            case '400':
93
                $this->status_code = "HTTP/1.0 400 Bad Request";
94
                break;
95
        }
96
        return $this;
97
    }
98
99
    /**
100
     * Método que procesa la plantilla
101
     *
102
     * @param string $tpl
103
     * @param array $vars
104
     * @param array $cookies
105
     *
106
     * @return string HTML
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

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

Loading history...
107
     */
108
    public function render($tpl, array $vars = array(), array $cookies = array())
109
    {
110
        Logger::log('Start render response');
111
        $vars = ResponseHelper::setDebugHeaders($vars);
112
        $output = $this->dump($tpl, $vars);
113
114
        return $this->output($output, 'text/html', $cookies);
115
    }
116
117
    /**
118
     * Servicio que establece las cabeceras de la respuesta
119
     * @param string $contentType
120
     * @param array $cookies
121
     */
122 1
    private function setReponseHeaders($contentType = 'text/html', array $cookies = array())
123
    {
124
        $config = Config::getInstance();
125
        $powered = $config->get("poweredBy");
126 1
        if (empty($powered)) {
127 1
            $powered = "@c15k0";
128 1
        }
129 1
        header("X-Powered-By: $powered");
130
        ResponseHelper::setStatusHeader($this->status_code);
131
        ResponseHelper::setAuthHeaders($this->public_zone);
132
        ResponseHelper::setCookieHeaders($cookies);
133
        header('Content-type: ' . $contentType);
134
135
    }
136
137
    /**
138
     * Servicio que devuelve el output
139
     * @param string $output
140
     * @param string $contentType
141
     * @param array $cookies
142
     * @return string HTML
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

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

Loading history...
143
     */
144
    public function output($output = '', $contentType = 'text/html', array $cookies = array())
145
    {
146
        Logger::log('Start output response');
147
        ob_start();
148
        $this->setReponseHeaders($contentType, $cookies);
149
        header('Content-length: ' . strlen($output));
150
151
        $cache = Cache::needCache();
152
        if (false !== $cache && $this->status_code === Template::STATUS_OK && $this->debug === false) {
153
            Logger::log('Saving output response into cache');
154
            $cacheName = $this->cache->getRequestCacheHash();
155
            $this->cache->storeData("json" . DIRECTORY_SEPARATOR . $cacheName, $output);
156
            $this->cache->storeData("json" . DIRECTORY_SEPARATOR . $cacheName . ".headers", headers_list(), Cache::JSON);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 121 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...
157
        }
158
        echo $output;
159
160
        ob_flush();
161
        ob_end_clean();
162
        Logger::log('End output response');
163
        $this->closeRender();
164
    }
165
166
    /**
167
     * Método que cierra y limpia los buffers de salida
168
     */
169
    public function closeRender()
170
    {
171
        Logger::log('Close template render');
172
        Security::getInstance()->setSessionKey("lastRequest", array(
173
            "url" => Request::getInstance()->getRootUrl() . Request::requestUri(),
174
            "ts" => microtime(true),
175
        ));
176
        Security::getInstance()->updateSession();
177
        Logger::log('End request: ' . Request::requestUri(), LOG_INFO);
178
        exit;
179
    }
180
181
    /**
182
     * Método que devuelve los datos cacheados con las cabeceras que tenía por entonces
183
     * @param string $data
184
     * @param array $headers
185
     */
186
    public function renderCache($data, $headers = array())
187
    {
188
        ob_start();
189
        for ($i = 0, $ct = count($headers); $i < $ct; $i++) {
190
            header($headers[$i]);
191
        }
192
        echo $data;
193
        ob_flush();
194
        ob_end_clean();
195
        $this->closeRender();
196
    }
197
198
    /**
199
     * Método que añade una nueva ruta al path de Twig
200
     * @param $path
201
     * @param $domain
202
     *
203
     * @return Template
204
     */
205 1
    public function addPath($path, $domain = '')
206
    {
207 1
        $this->tpl->getLoader()->addPath($path, $domain);
208 1
        return $this;
209
    }
210
211
    /**
212
     * Método que devuelve el contenido de una plantilla
213
     * @param string $tpl
214
     * @param array $vars
215
     * @return string
216
     */
217
    public function dump($tpl, array $vars = array())
218
    {
219
        $vars["__user__"] = Security::getInstance()->getUser();
220
        $vars["__admin__"] = Security::getInstance()->getAdmin();
221
        $vars["__profiles__"] = Security::getCleanProfiles();
222
        $vars["__flash__"] = Security::getInstance()->getFlashes();
223
        $dump = '';
224
        try {
225
            $dump = $this->tpl->render($tpl, $vars);
226
        } catch (\Exception $e) {
227
            Logger::log($e->getMessage(), LOG_ERR);
228
        }
229
        return $dump;
230
    }
231
232
    /**
233
     * Método que añade una función al motor de plantillas
234
     * @param string $templateFunction
235
     * @param $functionName
236
     *
237
     * @return Template
238
     */
239 1
    protected function addTemplateFunction($templateFunction, $functionName)
240
    {
241 1
        $function = new \Twig_SimpleFunction($templateFunction, $functionName);
242 1
        $this->tpl->addFunction($function);
243 1
        return $this;
244
    }
245
246
    /**
247
     * Funcion Twig para los assets en las plantillas
248
     * @return Template
249
     */
250 1
    private function addAssetFunction()
251
    {
252 1
        return $this->addTemplateFunction("asset", TemplateFunctions::ASSETS_FUNCTION);
253
    }
254
255
    /**
256
     * Función que pinta un formulario
257
     * @return Template
258
     */
259 1
    private function addFormsFunction()
260
    {
261 1
        return $this->addTemplateFunction("form", TemplateFunctions::FORM_FUNCTION);
262
    }
263
264
    /**
265
     * Función que pinta un campo de un formulario
266
     * @return Template
267
     */
268 1
    private function addFormWidgetFunction()
269
    {
270 1
        return $this->addTemplateFunction("form_widget", TemplateFunctions::WIDGET_FUNCTION);
271
    }
272
273
    /**
274
     * Función que pinta un botón de un formulario
275
     * @return Template
276
     */
277 1
    private function addFormButtonFunction()
278
    {
279 1
        return $this->addTemplateFunction("form_button", TemplateFunctions::BUTTON_FUNCTION);
280
    }
281
282
    /**
283
     * Método que devuelve un parámetro de configuración en la plantilla
284
     * @return Template
285
     */
286 1
    private function addConfigFunction()
287
    {
288 1
        return $this->addTemplateFunction("get_config", TemplateFunctions::CONFIG_FUNCTION);
289
    }
290
291
    /**
292
     * Método que añade la función path a Twig
293
     * @return Template
294
     */
295 1
    private function addRouteFunction()
296
    {
297 1
        return $this->addTemplateFunction("path", TemplateFunctions::ROUTE_FUNCTION);
298
    }
299
300
    /**
301
     * Método que copia directamente el recurso solicitado a la carpeta pública
302
     * @return Template
303
     */
304 1
    private function addResourceFunction()
305
    {
306 1
        return $this->addTemplateFunction("resource", TemplateFunctions::RESOURCE_FUNCTION);
307
    }
308
309
    /**
310
     * @return Template
311
     */
312 1
    private function addSessionFunction()
313
    {
314 1
        return $this->addTemplateFunction("session", TemplateFunctions::SESSION_FUNCTION);
315
    }
316
317
    /**
318
     * @return Template
319
     */
320 1
    private function addExistsFlashFunction()
321
    {
322 1
        return $this->addTemplateFunction("existsFlash", TemplateFunctions::EXISTS_FLASH_FUNCTION);
323
    }
324
325
    /**
326
     * @return Template
327
     */
328 1
    private function addGetFlashFunction()
329
    {
330 1
        return $this->addTemplateFunction("getFlash", TemplateFunctions::GET_FLASH_FUNCTION);
331
    }
332
333
    /**
334
     * Servicio que regenera todas las plantillas
335
     * @return array
336
     */
337
    public function regenerateTemplates()
338
    {
339
        $this->generateTemplatesCache();
340
        $domains = Cache::getInstance()->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 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...
341
        $translations = [];
342
        if (is_array($domains)) {
343
            $translations = $this->parsePathTranslations($domains);
344
        }
345
        $translations[] = _("Plantillas regeneradas correctamente");
346
        return $translations;
347
    }
348
349
    /**
350
     * @param $tplDir
351
     * @param string $domain
352
     *
353
     * @return mixed
354
     */
355
    protected function generateTemplate($tplDir, $domain = '')
356
    {
357
        $templatesDir = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tplDir), \RecursiveIteratorIterator::LEAVES_ONLY);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 138 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...
358
        foreach ($templatesDir as $file) {
359
            // force compilation
360
            if ($file->isFile()) {
361
                try {
362
                    $this->tpl->loadTemplate(str_replace($tplDir . '/', '', $file));
363
                } catch (\Exception $e) {
364
                    Logger::log($e->getMessage(), LOG_ERR);
365
                    throw $e;
366
                }
367
            }
368
        }
369
        return str_replace("%d", $domain, str_replace("%s", $tplDir, _("Generando plantillas en path '%s' para el dominio '%d'")));
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...
370
    }
371
372
    /**
373
     * Método que extrae el path de un string
374
     * @param $path
375
     *
376
     * @return string
377
     */
378
    public static function extractPath($path)
379
    {
380
        $explodePath = explode(DIRECTORY_SEPARATOR, $path);
381
        $realPath = array();
382
        for ($i = 0, $parts = count($explodePath) - 1; $i < $parts; $i++) {
383
            $realPath[] = $explodePath[$i];
384
        }
385
        return implode(DIRECTORY_SEPARATOR, $realPath);
386
    }
387
388
    /**
389
     * Método que devuelve los dominios de una plataforma
390
     * @param bool $append
391
     * @return array
392
     */
393
    static public function getDomains($append = false)
394
    {
395
        $domains = Router::getInstance()->getDomains();
396
        if ($append) {
397
            foreach ($domains as &$domain) {
398
                foreach ($domain as &$path) {
399
                    $path .= DIRECTORY_SEPARATOR;
400
                }
401
            }
402
        }
403
        return $domains;
404
    }
405
406
    /**
407
     * Método que añade todas las funciones de las plantillas
408
     */
409 1
    private function addTemplateFunctions()
410
    {
411
        //Asignamos las funciones especiales
412 1
        $this->addAssetFunction()
413 1
            ->addFormsFunction()
414 1
            ->addFormWidgetFunction()
415 1
            ->addFormButtonFunction()
416 1
            ->addConfigFunction()
417 1
            ->addRouteFunction()
418 1
            ->addSessionFunction()
419 1
            ->addExistsFlashFunction()
420 1
            ->addGetFlashFunction()
421 1
            ->addResourceFunction();
422 1
    }
423
424
    /**
425
     * Método que devuelve el motod de plantillas
426
     * @return \Twig_Environment
427
     */
428
    public function getTemplateEngine()
429
    {
430
        return $this->tpl;
431
    }
432
433
    /**
434
     * Method that extract all domains for using them with the templates
435
     */
436 1
    private function loadDomains()
437
    {
438 1
        $domains = Cache::getInstance()->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 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...
439 1
        if(null !== $domains) {
440 1
            foreach($domains as $domain => $paths) {
441 1
                $this->addPath($paths['template'], preg_replace('/(@|\/)/', '', $domain));
442 1
            }
443 1
        }
444 1
    }
445
446
    /**
447
     * Método que inicializa el motor de plantillas
448
     */
449 1
    private function setup()
450
    {
451 1
        $this->debug = Config::getInstance()->getDebugMode() ?: FALSE;
452 1
        $this->cache = Cache::getInstance();
453 1
        $loader = new \Twig_Loader_Filesystem(Config::getInstance()->getTemplatePath());
454 1
        $this->tpl = new \Twig_Environment($loader, array(
455 1
            'cache' => Config::getInstance()->getCachePath() . DIRECTORY_SEPARATOR . 'twig',
456 1
            'debug' => (bool)$this->debug,
457 1
            'auto_reload' => Config::getParam('twig.auto_reload', TRUE),
458 1
        ));
459 1
        $this->loadDomains();
460 1
    }
461
462
    /**
463
     * Método que inyecta los parseadores
464
     */
465 1
    private function addTemplateTokens()
466
    {
467
        //Añadimos las extensiones de los tags
468 1
        $this->tpl->addTokenParser(new AssetsTokenParser("css"));
469 1
        $this->tpl->addTokenParser(new AssetsTokenParser("js"));
470 1
    }
471
472
    /**
473
     * Método que inyecta las optimizaciones al motor de la plantilla
474
     */
475 1
    private function optimizeTemplates()
476
    {
477
        //Optimizamos
478 1
        $this->tpl->addExtension(new \Twig_Extensions_Extension_I18n());
479 1
    }
480
481
    /**
482
     * Method that extract all path tag for extracting translations
483
     * @param array $domains
484
     *
485
     * @return array
486
     */
487
    private function parsePathTranslations($domains)
488
    {
489
        $translations = array();
490
        if (!empty($domains)) {
491
            foreach ($domains as $domain => $paths) {
492
                if (strlen($domain) && array_key_exists("template", $paths)) {
493
                    $this->addPath($paths["template"], $domain);
494
                    $translations[] = $this->generateTemplate($paths["template"], $domain);
495
                }
496
            }
497
        }
498
499
        return $translations;
500
    }
501
502
    /**
503
     * Method that generate all template caches
504
     */
505
    private function generateTemplatesCache()
506
    {
507
        /** @var \Twig_Loader_Filesystem $loader */
508
        $loader = $this->tpl->getLoader();
509
        $availablePaths = $loader->getPaths();
510
        if (!empty($availablePaths)) {
511
            foreach ($availablePaths as $path) {
512
                $this->generateTemplate($path);
513
            }
514
        }
515
    }
516
}
517