Passed
Push — devel-3.0 ( e32256...e49526 )
by Rubén
04:31
created

Template::get()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * sysPass
4
 *
5
 * @author    nuxsmin
6
 * @link      https://syspass.org
7
 * @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
8
 *
9
 * This file is part of sysPass.
10
 *
11
 * sysPass is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU General Public License as published by
13
 * the Free Software Foundation, either version 3 of the License, or
14
 * (at your option) any later version.
15
 *
16
 * sysPass is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 *  along with sysPass.  If not, see <http://www.gnu.org/licenses/>.
23
 */
24
25
namespace SP\Mvc\View;
26
27
defined('APP_ROOT') || die();
28
29
use SP\Core\Exceptions\FileNotFoundException;
30
use SP\Core\UI\Theme;
31
use SP\Core\UI\ThemeInterface;
32
33
/**
34
 * Class Template
35
 *
36
 * A very basic template engine...
37
 *
38
 * Idea original de http://www.sitepoint.com/author/agervasio/
39
 * publicada en http://www.sitepoint.com/flexible-view-manipulation-1/
40
 *
41
 */
42
final class Template
43
{
44
    const TEMPLATE_EXTENSION = '.inc';
45
    const PARTIALS_DIR = '_partials';
46
    const LAYOUTS_DIR = '_layouts';
47
48
    /**
49
     * @var ThemeInterface
50
     */
51
    protected $theme;
52
    /**
53
     * @var array List of templates to load into the view
54
     */
55
    private $templates = [];
56
    /**
57
     * @var TemplateVarCollection Template's variables collection
58
     */
59
    private $vars;
60
    /**
61
     * @var string Base path for imcluding templates
62
     */
63
    private $base;
64
    /**
65
     * @var array
66
     */
67
    private $contentTemplates = [];
68
    /**
69
     * @var bool
70
     */
71
    private $upgraded = false;
72
73
    /**
74
     * @param Theme $theme
75
     */
76
    public function __construct(Theme $theme)
77
    {
78
        $this->theme = $theme;
79
        $this->vars = new TemplateVarCollection();
80
    }
81
82
    /**
83
     * Añadir una nueva plantilla al array de plantillas de la clase
84
     *
85
     * @param string $name Con el nombre del archivo de plantilla
86
     * @param string $base Directorio base para la plantilla
87
     *
88
     * @return bool
89
     */
90
    public function addContentTemplate($name, $base = null)
91
    {
92
        try {
93
            $template = $this->checkTemplate($name, $base);
94
            $this->setContentTemplate($template, $name);
95
        } catch (FileNotFoundException $e) {
96
            return '';
0 ignored issues
show
Bug Best Practice introduced by
The expression return '' returns the type string which is incompatible with the documented return type boolean.
Loading history...
97
        }
98
99
        return $template;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $template returns the type string which is incompatible with the documented return type boolean.
Loading history...
100
    }
101
102
    /**
103
     * Comprobar si un archivo de plantilla existe y se puede leer
104
     *
105
     * @param string $template Con el nombre del archivo
106
     *
107
     * @return string La ruta al archivo de la plantilla
108
     *
109
     * @param string $base     Directorio base para la plantilla
110
     *
111
     * @throws \SP\Core\Exceptions\FileNotFoundException
112
     */
113
    private function checkTemplate($template, $base = null)
114
    {
115
        $base = null !== $base ? $base : (null !== $this->base ? $this->base : null);
116
117
        if ($base === null) {
118
            $templateFile = $this->theme->getViewsPath() . DIRECTORY_SEPARATOR . $template . self::TEMPLATE_EXTENSION;
119
        } elseif (is_dir($base)) {
120
            $templateFile = $base . DIRECTORY_SEPARATOR . $template . self::TEMPLATE_EXTENSION;
121
        } else {
122
            $templateFile = $this->theme->getViewsPath() . DIRECTORY_SEPARATOR . $base . DIRECTORY_SEPARATOR . $template . self::TEMPLATE_EXTENSION;
123
        }
124
125
        if (!is_readable($templateFile)) {
126
            $msg = sprintf(__('No es posible obtener la plantilla "%s" : %s'), $templateFile, $template);
127
128
            logger($msg);
129
130
            throw new FileNotFoundException($msg);
131
        }
132
133
        return $templateFile;
134
    }
135
136
    /**
137
     * Añadir un nuevo archivo de plantilla al array de plantillas de contenido
138
     *
139
     * @param string $file Con el nombre del archivo
140
     * @param string $name Nombre de la plantilla
141
     */
142
    private function setContentTemplate($file, $name)
143
    {
144
        $this->contentTemplates[$name] = $file;
145
    }
146
147
    /**
148
     * Removes a template from the stack
149
     *
150
     * @param $name
151
     *
152
     * @return Template
153
     */
154
    public function removeTemplate($name)
155
    {
156
        unset($this->templates[$name]);
157
158
        return $this;
159
    }
160
161
    /**
162
     * Removes a template from the stack
163
     *
164
     * @param $name
165
     *
166
     * @return Template
167
     */
168
    public function removeContentTemplate($name)
169
    {
170
        unset($this->contentTemplates[$name]);
171
172
        return $this;
173
    }
174
175
    /**
176
     * Removes a template from the stack
177
     *
178
     * @param string $src Source template
179
     * @param string $dst Destination template
180
     * @param string $base
181
     *
182
     * @return mixed|string
183
     */
184
    public function replaceTemplate($src, $dst, $base)
185
    {
186
        try {
187
            if (isset($this->contentTemplates[$dst])) {
188
                $this->contentTemplates[$dst] = $this->checkTemplate($src, $base);
189
            }
190
        } catch (FileNotFoundException $e) {
191
            return '';
192
        }
193
194
        return $this->contentTemplates[$dst];
195
    }
196
197
    /**
198
     * Add partial template
199
     *
200
     * @param $partial
201
     */
202
    public function addPartial($partial)
203
    {
204
        $this->addTemplate($partial, self::PARTIALS_DIR);
205
    }
206
207
    /**
208
     * Añadir una nueva plantilla al array de plantillas de la clase
209
     *
210
     * @param string $name Con el nombre del archivo de plantilla
211
     * @param string $base Directorio base para la plantilla
212
     *
213
     * @return bool
214
     */
215
    public function addTemplate($name, $base = null)
216
    {
217
        try {
218
            $template = $this->checkTemplate($name, $base);
219
            $this->setTemplate($template, $name);
220
        } catch (FileNotFoundException $e) {
221
            return '';
0 ignored issues
show
Bug Best Practice introduced by
The expression return '' returns the type string which is incompatible with the documented return type boolean.
Loading history...
222
        }
223
224
        return $template;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $template returns the type string which is incompatible with the documented return type boolean.
Loading history...
225
    }
226
227
    /**
228
     * Añadir un nuevo archivo de plantilla al array de plantillas
229
     *
230
     * @param string $file Con el nombre del archivo
231
     * @param string $name Nombre de la plantilla
232
     */
233
    private function setTemplate($file, $name)
234
    {
235
        $this->templates[$name] = $file;
236
    }
237
238
    /**
239
     * Añadir una nueva plantilla dentro de una plantilla
240
     *
241
     * @param string $file Con el nombre del archivo de plantilla
242
     *
243
     * @return bool
244
     */
245
    public function includePartial($file)
246
    {
247
        return $this->includeTemplate($file, self::PARTIALS_DIR);
248
    }
249
250
    /**
251
     * Añadir una nueva plantilla dentro de una plantilla
252
     *
253
     * @param string $file Con el nombre del archivo de plantilla
254
     * @param string $base Directorio base para la plantilla
255
     *
256
     * @return bool
257
     */
258
    public function includeTemplate($file, $base = null)
259
    {
260
        try {
261
            return $this->checkTemplate($file, $base);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->checkTemplate($file, $base) returns the type string which is incompatible with the documented return type boolean.
Loading history...
262
        } catch (FileNotFoundException $e) {
263
            return false;
264
        }
265
    }
266
267
    /**
268
     * Overloading para controlar la devolución de atributos dinámicos.
269
     *
270
     * @param string $name Nombre del atributo
271
     *
272
     * @return null
273
     */
274
    public function __get($name)
275
    {
276
        return $this->get($name);
277
    }
278
279
    /**
280
     * Overloading para añadir nuevas variables en al array de variables dela plantilla
281
     * pasadas como atributos dinámicos de la clase
282
     *
283
     * @param string $name  Nombre del atributo
284
     * @param string $value Valor del atributo
285
     */
286
    public function __set($name, $value)
287
    {
288
        $this->vars->set($name, $value);
289
    }
290
291
    /**
292
     * Returns a variable value
293
     *
294
     * @param $name
295
     *
296
     * @return mixed
297
     */
298
    public function get($name)
299
    {
300
        if (!$this->vars->exists($name)) {
301
            logger(sprintf(__('No es posible obtener la variable "%s"'), $name), 'ERROR');
302
303
            return null;
304
//            throw new InvalidArgumentException(sprintf(__('No es posible obtener la variable "%s"'), $name));
305
        }
306
307
        return $this->vars->get($name);
308
    }
309
310
    /**
311
     * Overloading para comprobar si el atributo solicitado está declarado como variable
312
     * en el array de variables de la plantilla.
313
     *
314
     * @param string $name Nombre del atributo
315
     *
316
     * @return bool
317
     */
318
    public function __isset($name)
319
    {
320
        return $this->vars->exists($name);
321
    }
322
323
    /**
324
     * Overloading para eliminar una variable del array de variables de la plantilla pasado como
325
     * atributo dinámico de la clase
326
     *
327
     * @param string $name Nombre del atributo
328
     *
329
     * @return $this
330
     */
331
    public function __unset($name)
332
    {
333
        if (!$this->vars->exists($name)) {
334
            logger(sprintf(__('No es posible destruir la variable "%s"'), $name));
335
336
//            throw new InvalidArgumentException(sprintf(__('No es posible destruir la variable "%s"'), $name));
337
            return $this;
338
        }
339
340
        $this->vars->remove($name);
341
342
        return $this;
343
    }
344
345
    /**
346
     * Mostrar la plantilla solicitada.
347
     * La salida se almacena en buffer y se devuelve el contenido
348
     *
349
     * @return string Con el contenido del buffer de salida
350
     * @throws FileNotFoundException
351
     */
352
    public function render()
353
    {
354
        if (count($this->templates) === 0) {
355
            throw new FileNotFoundException(__('La plantilla no contiene archivos'));
356
        }
357
358
        $icons = $this->vars->get('icons');
0 ignored issues
show
Unused Code introduced by
The assignment to $icons is dead and can be removed.
Loading history...
359
        $configData = $this->vars->get('configData');
0 ignored issues
show
Unused Code introduced by
The assignment to $configData is dead and can be removed.
Loading history...
360
        $sk = $this->vars->get('sk');
0 ignored issues
show
Unused Code introduced by
The assignment to $sk is dead and can be removed.
Loading history...
361
362
        // An anonymous proxy function for handling views variables
363
        $_getvar = function ($key, $default = null) {
0 ignored issues
show
Unused Code introduced by
The assignment to $_getvar is dead and can be removed.
Loading history...
364
            if (DEBUG && !$this->vars->exists($key)) {
365
                logger(sprintf(__('No es posible obtener la variable "%s"'), $key), 'WARN');
366
            }
367
368
            return $this->vars->get($key, $default);
369
        };
370
371
        ob_start();
372
373
        // Añadimos las plantillas
374
        foreach ($this->templates as $template) {
375
            include_once $template;
376
        }
377
378
        return ob_get_clean();
379
    }
380
381
    /**
382
     * Anexar el valor de la variable al array de la misma en el array de variables
383
     *
384
     * @param      $name  string nombre de la variable
385
     * @param      $value mixed valor de la variable
386
     * @param      $index string índice del array
387
     * @param null $scope string ámbito de la variable
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $scope is correct as it would always require null to be passed?
Loading history...
388
     */
389
    public function append($name, $value, $scope = null, $index = null)
390
    {
391
        if (null !== $scope) {
0 ignored issues
show
introduced by
The condition null !== $scope is always false.
Loading history...
392
            $name = $scope . '_' . $name;
393
        }
394
395
        $var = $this->vars->get($name, []);
396
397
        if (null === $index) {
398
            $var[] = $value;
399
        } else {
400
            $var[$index] = $value;
401
        }
402
403
        $this->vars->set($name, $var);
404
    }
405
406
    /**
407
     * Reset de las plantillas añadidas
408
     */
409
    public function resetTemplates()
410
    {
411
        $this->templates = [];
412
413
        return $this;
414
    }
415
416
    /**
417
     * Reset de las plantillas añadidas
418
     */
419
    public function resetContentTemplates()
420
    {
421
        $this->contentTemplates = [];
422
423
        return $this;
424
    }
425
426
    /**
427
     * Reset de las plantillas añadidas
428
     */
429
    public function resetVariables()
430
    {
431
        $this->vars = [];
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type SP\Mvc\View\TemplateVarCollection of property $vars.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
432
    }
433
434
    /**
435
     * @return string
436
     */
437
    public function getBase()
438
    {
439
        return $this->base;
440
    }
441
442
    /**
443
     * @param string $base
444
     */
445
    public function setBase($base)
446
    {
447
        $this->base = $base;
448
    }
449
450
    /**
451
     * @return ThemeInterface
452
     */
453
    public function getTheme()
454
    {
455
        return $this->theme;
456
    }
457
458
    /**
459
     * Dumps current stored vars
460
     */
461
    public function dumpVars()
462
    {
463
        logger($this->vars);
464
    }
465
466
    /**
467
     * @return array
468
     */
469
    public function getContentTemplates()
470
    {
471
        return $this->contentTemplates;
472
    }
473
474
    /**
475
     * @return bool
476
     */
477
    public function hashContentTemplates()
478
    {
479
        return count($this->contentTemplates) > 0;
480
    }
481
482
    /**
483
     * @return array
484
     */
485
    public function getTemplates()
486
    {
487
        return $this->templates;
488
    }
489
490
    /**
491
     * Assigns the current templates to contentTemplates
492
     *
493
     * @return $this
494
     */
495
    public function upgrade()
496
    {
497
        if (count($this->templates) > 0) {
498
            $this->contentTemplates = $this->templates;
499
500
            $this->templates = [];
501
502
            $this->upgraded = true;
503
        }
504
505
        return $this;
506
    }
507
508
    /**
509
     * Crear la variable y asignarle un valor en el array de variables
510
     *
511
     * @param      $name  string nombre de la variable
512
     * @param      $value mixed valor de la variable
513
     * @param null $scope string ámbito de la variable
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $scope is correct as it would always require null to be passed?
Loading history...
514
     */
515
    public function assign($name, $value = '', $scope = null)
516
    {
517
        if (null !== $scope) {
0 ignored issues
show
introduced by
The condition null !== $scope is always false.
Loading history...
518
            $name = $scope . '_' . $name;
519
        }
520
521
        $this->vars->set($name, $value);
522
    }
523
524
    /**
525
     * @return bool
526
     */
527
    public function isUpgraded()
528
    {
529
        return $this->upgraded;
530
    }
531
}