Passed
Push — master ( e9d973...038fa0 )
by Fran
03:28
created

Template::getDomains()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 2
nop 1
dl 0
loc 12
ccs 0
cts 10
cp 0
crap 20
rs 9.2
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 1
    public function render($tpl, array $vars = array(), array $cookies = array())
109
    {
110 1
        Logger::log('Start render response');
111 1
        $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->load(str_replace($tplDir . '/', '', $file));
363
                } catch (\Exception $e) {
364
                    Logger::log($e->getMessage(), LOG_ERR, ['file' => $e->getFile(), 'line' => $e->getLine()]);
365
                }
366
            }
367
        }
368
        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...
369
    }
370
371
    /**
372
     * Método que extrae el path de un string
373
     * @param $path
374
     *
375
     * @return string
376
     */
377
    public static function extractPath($path)
378
    {
379
        $explodePath = explode(DIRECTORY_SEPARATOR, $path);
380
        $realPath = array();
381
        for ($i = 0, $parts = count($explodePath) - 1; $i < $parts; $i++) {
382
            $realPath[] = $explodePath[$i];
383
        }
384
        return implode(DIRECTORY_SEPARATOR, $realPath);
385
    }
386
387
    /**
388
     * Método que devuelve los dominios de una plataforma
389
     * @param bool $append
390
     * @return array
391
     */
392
    static public function getDomains($append = false)
393
    {
394
        $domains = Router::getInstance()->getDomains();
395
        if ($append) {
396
            foreach ($domains as &$domain) {
397
                foreach ($domain as &$path) {
398
                    $path .= DIRECTORY_SEPARATOR;
399
                }
400
            }
401
        }
402
        return $domains;
403
    }
404
405
    /**
406
     * Método que añade todas las funciones de las plantillas
407
     */
408 1
    private function addTemplateFunctions()
409
    {
410
        //Asignamos las funciones especiales
411 1
        $this->addAssetFunction()
412 1
            ->addFormsFunction()
413 1
            ->addFormWidgetFunction()
414 1
            ->addFormButtonFunction()
415 1
            ->addConfigFunction()
416 1
            ->addRouteFunction()
417 1
            ->addSessionFunction()
418 1
            ->addExistsFlashFunction()
419 1
            ->addGetFlashFunction()
420 1
            ->addResourceFunction();
421 1
    }
422
423
    /**
424
     * Método que devuelve el motod de plantillas
425
     * @return \Twig_Environment
426
     */
427
    public function getTemplateEngine()
428
    {
429
        return $this->tpl;
430
    }
431
432
    /**
433
     * Method that extract all domains for using them with the templates
434
     */
435 1
    private function loadDomains()
436
    {
437 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...
438 1
        if(null !== $domains) {
439 1
            foreach($domains as $domain => $paths) {
440 1
                $this->addPath($paths['template'], preg_replace('/(@|\/)/', '', $domain));
441 1
            }
442 1
        }
443 1
    }
444
445
    /**
446
     * Método que inicializa el motor de plantillas
447
     */
448 1
    private function setup()
449
    {
450 1
        $this->debug = Config::getInstance()->getDebugMode() ?: FALSE;
451 1
        $this->cache = Cache::getInstance();
452 1
        $loader = new \Twig_Loader_Filesystem(Config::getInstance()->getTemplatePath());
453 1
        $this->tpl = new \Twig_Environment($loader, array(
454 1
            'cache' => Config::getInstance()->getCachePath() . DIRECTORY_SEPARATOR . 'twig',
455 1
            'debug' => (bool)$this->debug,
456 1
            'auto_reload' => Config::getParam('twig.auto_reload', TRUE),
457 1
        ));
458 1
        $this->loadDomains();
459 1
    }
460
461
    /**
462
     * Método que inyecta los parseadores
463
     */
464 1
    private function addTemplateTokens()
465
    {
466
        //Añadimos las extensiones de los tags
467 1
        $this->tpl->addTokenParser(new AssetsTokenParser("css"));
468 1
        $this->tpl->addTokenParser(new AssetsTokenParser("js"));
469 1
    }
470
471
    /**
472
     * Método que inyecta las optimizaciones al motor de la plantilla
473
     */
474 1
    private function optimizeTemplates()
475
    {
476
        //Optimizamos
477 1
        $this->tpl->addExtension(new \Twig_Extensions_Extension_I18n());
478 1
    }
479
480
    /**
481
     * Method that extract all path tag for extracting translations
482
     * @param array $domains
483
     *
484
     * @return array
485
     */
486
    private function parsePathTranslations($domains)
487
    {
488
        $translations = array();
489
        if (!empty($domains)) {
490
            foreach ($domains as $domain => $paths) {
491
                if (strlen($domain) && array_key_exists("template", $paths)) {
492
                    $this->addPath($paths["template"], $domain);
493
                    $translations[] = $this->generateTemplate($paths["template"], $domain);
494
                }
495
            }
496
        }
497
498
        return $translations;
499
    }
500
501
    /**
502
     * Method that generate all template caches
503
     */
504
    private function generateTemplatesCache()
505
    {
506
        /** @var \Twig_Loader_Filesystem $loader */
507
        $loader = $this->tpl->getLoader();
508
        $availablePaths = $loader->getPaths();
509
        if (!empty($availablePaths)) {
510
            foreach ($availablePaths as $path) {
511
                $this->generateTemplate($path);
512
            }
513
        }
514
    }
515
}
516