Test Failed
Push — master ( 21e806...ed25dd )
by Fran
05:25 queued 02:04
created

Template::extractPath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 9
ccs 0
cts 6
cp 0
crap 6
rs 9.9666
c 0
b 0
f 0
1
<?php
2
namespace PSFS\base;
3
4
use PSFS\base\config\Config;
5
use PSFS\base\extension\AssetsTokenParser;
6
use PSFS\base\extension\CustomTranslateExtension;
7
use PSFS\base\extension\TemplateFunctions;
8
use PSFS\base\types\helpers\GeneratorHelper;
9
use PSFS\base\types\helpers\ResponseHelper;
10
use PSFS\base\types\traits\OutputTrait;
11
use PSFS\base\types\traits\RouteTrait;
12
use PSFS\base\types\traits\SingletonTrait;
13
14
/**
15
 * Class Template
16
 * @package PSFS\base
17
 */
18
class Template
19
{
20
    use SingletonTrait;
21
    use OutputTrait;
22
    use RouteTrait;
23
    const STATUS_OK = 'HTTP/1.0 200 OK';
24
    /**
25
     * @var \Twig_Environment tpl
26
     */
27
    protected $tpl;
28
    protected $filters = array();
29
30
    /**
31
     * Constructor por defecto
32
     */
33 2
    public function __construct()
34
    {
35 2
        $this->setup();
36
        $this->addTemplateFunctions();
37
        $this->addTemplateTokens();
38
        $this->optimizeTemplates();
39
    }
40
41
    /**
42
     * Método que devuelve el loader del Template
43
     * @return \Twig_LoaderInterface
44
     */
45
    public function getLoader()
46
    {
47
        return $this->tpl->getLoader();
48
    }
49
50
    /**
51
     * Método que activa la zona pública
52
     * @param bool $public
53
     *
54
     * @return Template
55
     */
56
    public function setPublicZone($public = true)
57
    {
58
        $this->public_zone = $public;
59
        return $this;
60
    }
61
62
    /**
63
     * @return bool
64
     */
65
    public function isPublicZone() {
66
        return $this->public_zone;
67
    }
68
69
    /**
70
     * Método que procesa la plantilla
71
     *
72
     * @param string $tpl
73
     * @param array $vars
74
     * @param array $cookies
75
     *
76
     * @return string HTML
77
     */
78
    public function render($tpl, array $vars = array(), array $cookies = array())
79
    {
80
        Logger::log('Start render response');
81
        $vars = ResponseHelper::setDebugHeaders($vars);
82
        $output = $this->dump($tpl, $vars);
83
84
        return $this->output($output, 'text/html', $cookies);
85
    }
86
87
    /**
88
     * Método que añade una nueva ruta al path de Twig
89
     * @param $path
90
     * @param $domain
91
     *
92
     * @return Template
93
     */
94
    public function addPath($path, $domain = '')
95
    {
96
        $this->tpl->getLoader()->addPath($path, $domain);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Twig_LoaderInterface as the method addPath() does only exist in the following implementations of said interface: Twig\Loader\FilesystemLoader, Twig_Loader_Filesystem.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
97
        return $this;
98
    }
99
100
    /**
101
     * Método que devuelve el contenido de una plantilla
102
     * @param string $tpl
103
     * @param array $vars
104
     * @return string
105
     */
106
    public function dump($tpl, array $vars = array())
107
    {
108
        $vars["__user__"] = Security::getInstance()->getUser();
109
        $vars["__admin__"] = Security::getInstance()->getAdmin();
110
        $vars["__profiles__"] = Security::getCleanProfiles();
111
        $vars["__flash__"] = Security::getInstance()->getFlashes();
112
        $vars["__get__"] = Request::getInstance()->getQueryParams();
113
        $vars["__post__"] = Request::getInstance()->getData();
114
        $dump = '';
115
        try {
116
            $dump = $this->tpl->render($tpl, $vars);
117
        } catch (\Exception $e) {
118
            Logger::log($e->getMessage(), LOG_ERR);
119
        }
120
        return $dump;
121
    }
122
123
    /**
124
     * Método que añade una función al motor de plantillas
125
     * @param string $templateFunction
126
     * @param $functionName
127
     *
128
     * @return Template
129
     */
130
    protected function addTemplateFunction($templateFunction, $functionName)
131
    {
132
        $function = new \Twig_SimpleFunction($templateFunction, $functionName);
133
        $this->tpl->addFunction($function);
134
        return $this;
135
    }
136
137
    /**
138
     * Servicio que regenera todas las plantillas
139
     * @return array
140
     */
141
    public function regenerateTemplates()
142
    {
143
        $this->generateTemplatesCache();
144
        $domains = Cache::getInstance()->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . "domains.json", Cache::JSON, true);
145
        $translations = [];
146
        if (is_array($domains)) {
147
            $translations = $this->parsePathTranslations($domains);
148
        }
149
        $translations[] = _("Plantillas regeneradas correctamente");
150
        return $translations;
151
    }
152
153
    /**
154
     * @param $tplDir
155
     * @param string $domain
156
     *
157
     * @return mixed
158
     */
159
    protected function generateTemplate($tplDir, $domain = '')
160
    {
161
        $templatesDir = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tplDir), \RecursiveIteratorIterator::LEAVES_ONLY);
162
        foreach ($templatesDir as $file) {
163
            // force compilation
164
            if ($file->isFile()) {
165
                try {
166
                    $this->tpl->load(str_replace($tplDir . '/', '', $file));
167
                } catch (\Exception $e) {
168
                    Logger::log($e->getMessage(), LOG_ERR, ['file' => $e->getFile(), 'line' => $e->getLine()]);
169
                }
170
            }
171
        }
172
        return str_replace("%d", $domain, str_replace("%s", $tplDir, _("Generando plantillas en path '%s' para el dominio '%d'")));
173
    }
174
175
    /**
176
     * Método que extrae el path de un string
177
     * @param $path
178
     *
179
     * @return string
180
     */
181
    public static function extractPath($path)
182
    {
183
        $explodePath = explode(DIRECTORY_SEPARATOR, $path);
184
        $realPath = array();
185
        for ($i = 0, $parts = count($explodePath) - 1; $i < $parts; $i++) {
186
            $realPath[] = $explodePath[$i];
187
        }
188
        return implode(DIRECTORY_SEPARATOR, $realPath);
189
    }
190
191
    /**
192
     * Método que devuelve los dominios de una plataforma
193
     * @param bool $append
194
     * @return array
195
     */
196
    static public function getDomains($append = false)
197
    {
198
        $domains = Router::getInstance()->getDomains();
199
        if ($append) {
200
            foreach ($domains as &$domain) {
201
                foreach ($domain as &$path) {
202
                    $path .= DIRECTORY_SEPARATOR;
203
                }
204
            }
205
        }
206
        return $domains;
207
    }
208
209
    /**
210
     * Método que añade todas las funciones de las plantillas
211
     */
212
    private function addTemplateFunctions()
213
    {
214
        //Asignamos las funciones especiales
215
        $functions = [
216
            'asset' => TemplateFunctions::ASSETS_FUNCTION,
217
            'form' => TemplateFunctions::FORM_FUNCTION,
218
            'form_widget' => TemplateFunctions::WIDGET_FUNCTION,
219
            'form_button' => TemplateFunctions::BUTTON_FUNCTION,
220
            'get_config' => TemplateFunctions::CONFIG_FUNCTION,
221
            'path' => TemplateFunctions::ROUTE_FUNCTION,
222
            'resource' => TemplateFunctions::RESOURCE_FUNCTION,
223
            'session' => TemplateFunctions::SESSION_FUNCTION,
224
            'existsFlash' => TemplateFunctions::EXISTS_FLASH_FUNCTION,
225
            'getFlash' => TemplateFunctions::GET_FLASH_FUNCTION,
226
            'getQuery' => TemplateFunctions::GET_QUERY_FUNCTION,
227
        ];
228
        foreach($functions as $name => $function) {
229
            $this->addTemplateFunction($name, $function);
230
        }
231
    }
232
233
    /**
234
     * Método que devuelve el motod de plantillas
235
     * @return \Twig_Environment
236
     */
237
    public function getTemplateEngine()
238
    {
239
        return $this->tpl;
240
    }
241
242
    /**
243
     * Method that extract all domains for using them with the templates
244
     */
245 2
    private function loadDomains()
246
    {
247 2
        $domains = Cache::getInstance()->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . 'domains.json', Cache::JSON, true);
248
        if (null !== $domains) {
249
            foreach ($domains as $domain => $paths) {
250
                $this->addPath($paths['template'], preg_replace('/(@|\/)/', '', $domain));
251
            }
252
        }
253
    }
254
255
    /**
256
     * Método que inicializa el motor de plantillas
257
     */
258 2
    private function setup()
259
    {
260 2
        $loader = new \Twig_Loader_Filesystem(GeneratorHelper::getTemplatePath());
261 2
        $this->tpl = new \Twig_Environment($loader, array(
262 2
            'cache' => CACHE_DIR . DIRECTORY_SEPARATOR . 'twig',
263 2
            'debug' => (bool)$this->debug,
264 2
            'auto_reload' => Config::getParam('twig.autoreload', TRUE),
265
        ));
266 2
        $this->loadDomains();
267
    }
268
269
    /**
270
     * Método que inyecta los parseadores
271
     */
272
    private function addTemplateTokens()
273
    {
274
        //Añadimos las extensiones de los tags
275
        $this->tpl->addTokenParser(new AssetsTokenParser("css"));
276
        $this->tpl->addTokenParser(new AssetsTokenParser("js"));
277
    }
278
279
    /**
280
     * Método que inyecta las optimizaciones al motor de la plantilla
281
     */
282
    private function optimizeTemplates()
283
    {
284
        //Optimizamos
285
        $this->tpl->addExtension(new CustomTranslateExtension());
286
    }
287
288
    /**
289
     * Method that extract all path tag for extracting translations
290
     * @param array $domains
291
     *
292
     * @return array
293
     */
294
    private function parsePathTranslations($domains)
295
    {
296
        $translations = array();
297
        if (!empty($domains)) {
298
            foreach ($domains as $domain => $paths) {
299
                if (strlen($domain) && array_key_exists("template", $paths)) {
300
                    $this->addPath($paths["template"], $domain);
301
                    $translations[] = $this->generateTemplate($paths["template"], $domain);
302
                }
303
            }
304
        }
305
306
        return $translations;
307
    }
308
309
    /**
310
     * Method that generate all template caches
311
     */
312
    private function generateTemplatesCache()
313
    {
314
        /** @var \Twig_Loader_Filesystem $loader */
315
        $loader = $this->tpl->getLoader();
316
        $availablePaths = $loader->getPaths();
317
        if (!empty($availablePaths)) {
318
            foreach ($availablePaths as $path) {
319
                $this->generateTemplate($path);
320
            }
321
        }
322
    }
323
}
324