Test Failed
Push — master ( cc821f...fdc4d2 )
by Fran
09:36 queued 04:02
created

Template::parsePathTranslations()   B

Complexity

Conditions 5
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 8.125

Importance

Changes 0
Metric Value
cc 5
eloc 8
nc 2
nop 1
dl 0
loc 14
ccs 4
cts 8
cp 0.5
crap 8.125
rs 8.8571
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\TemplateFunctions;
7
use PSFS\base\types\helpers\GeneratorHelper;
8
use PSFS\base\types\helpers\ResponseHelper;
9
use PSFS\base\types\traits\OutputTrait;
10
use PSFS\base\types\traits\RouteTrait;
11
use PSFS\base\types\traits\SingletonTrait;
12
13
/**
14
 * Class Template
15
 * @package PSFS\base
16
 */
17
class Template
18
{
19
    use SingletonTrait;
20
    use OutputTrait;
21
    use RouteTrait;
22
    const STATUS_OK = 'HTTP/1.0 200 OK';
23
    /**
24
     * @var \Twig_Environment tpl
25
     */
26
    protected $tpl;
27
    protected $filters = array();
28
29
    /**
30
     * Constructor por defecto
31
     */
32 1
    public function __construct()
33
    {
34 1
        $this->setup();
35 1
        $this->addTemplateFunctions();
36 1
        $this->addTemplateTokens();
37 1
        $this->optimizeTemplates();
38 1
    }
39
40
    /**
41
     * Método que devuelve el loader del Template
42
     * @return \Twig_LoaderInterface
43
     */
44 1
    public function getLoader()
45
    {
46 1
        return $this->tpl->getLoader();
47
    }
48
49
    /**
50
     * Método que activa la zona pública
51
     * @param bool $public
52
     *
53
     * @return Template
54
     */
55 1
    public function setPublicZone($public = true)
56
    {
57 1
        $this->public_zone = $public;
58 1
        return $this;
59
    }
60
61
    /**
62
     * @return bool
63
     */
64 1
    public function isPublicZone() {
65 1
        return $this->public_zone;
66
    }
67
68
    /**
69
     * Método que procesa la plantilla
70
     *
71
     * @param string $tpl
72
     * @param array $vars
73
     * @param array $cookies
74
     *
75
     * @return string HTML
76
     */
77
    public function render($tpl, array $vars = array(), array $cookies = array())
78
    {
79
        Logger::log('Start render response');
80
        $vars = ResponseHelper::setDebugHeaders($vars);
81
        $output = $this->dump($tpl, $vars);
82
83
        return $this->output($output, 'text/html', $cookies);
84
    }
85
86
    /**
87
     * Método que añade una nueva ruta al path de Twig
88
     * @param $path
89
     * @param $domain
90
     *
91
     * @return Template
92
     */
93
    public function addPath($path, $domain = '')
94
    {
95
        $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...
96
        return $this;
97
    }
98
99
    /**
100
     * Método que devuelve el contenido de una plantilla
101
     * @param string $tpl
102
     * @param array $vars
103
     * @return string
104
     */
105 1
    public function dump($tpl, array $vars = array())
106
    {
107 1
        $vars["__user__"] = Security::getInstance()->getUser();
108 1
        $vars["__admin__"] = Security::getInstance()->getAdmin();
109 1
        $vars["__profiles__"] = Security::getCleanProfiles();
110 1
        $vars["__flash__"] = Security::getInstance()->getFlashes();
111 1
        $vars["__get__"] = Request::getInstance()->getQueryParams();
112 1
        $vars["__post__"] = Request::getInstance()->getData();
113 1
        $dump = '';
114
        try {
115 1
            $dump = $this->tpl->render($tpl, $vars);
116
        } catch (\Exception $e) {
117
            Logger::log($e->getMessage(), LOG_ERR);
118
        }
119 1
        return $dump;
120
    }
121
122
    /**
123
     * Método que añade una función al motor de plantillas
124
     * @param string $templateFunction
125
     * @param $functionName
126
     *
127
     * @return Template
128
     */
129 1
    protected function addTemplateFunction($templateFunction, $functionName)
130
    {
131 1
        $function = new \Twig_SimpleFunction($templateFunction, $functionName);
132 1
        $this->tpl->addFunction($function);
133 1
        return $this;
134
    }
135
136
    /**
137
     * Servicio que regenera todas las plantillas
138
     * @return array
139
     */
140 1
    public function regenerateTemplates()
141
    {
142 1
        $this->generateTemplatesCache();
143 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...
144 1
        $translations = [];
145 1
        if (is_array($domains)) {
146 1
            $translations = $this->parsePathTranslations($domains);
147
        }
148 1
        $translations[] = _("Plantillas regeneradas correctamente");
149 1
        return $translations;
150
    }
151
152
    /**
153
     * @param $tplDir
154
     * @param string $domain
155
     *
156
     * @return mixed
157
     */
158 1
    protected function generateTemplate($tplDir, $domain = '')
159
    {
160 1
        $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...
161 1
        foreach ($templatesDir as $file) {
162
            // force compilation
163 1
            if ($file->isFile()) {
164
                try {
165 1
                    $this->tpl->load(str_replace($tplDir . '/', '', $file));
166 1
                } catch (\Exception $e) {
167 1
                    Logger::log($e->getMessage(), LOG_ERR, ['file' => $e->getFile(), 'line' => $e->getLine()]);
168
                }
169
            }
170
        }
171 1
        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...
172
    }
173
174
    /**
175
     * Método que extrae el path de un string
176
     * @param $path
177
     *
178
     * @return string
179
     */
180 1
    public static function extractPath($path)
181
    {
182 1
        $explodePath = explode(DIRECTORY_SEPARATOR, $path);
183 1
        $realPath = array();
184 1
        for ($i = 0, $parts = count($explodePath) - 1; $i < $parts; $i++) {
185 1
            $realPath[] = $explodePath[$i];
186
        }
187 1
        return implode(DIRECTORY_SEPARATOR, $realPath);
188
    }
189
190
    /**
191
     * Método que devuelve los dominios de una plataforma
192
     * @param bool $append
193
     * @return array
194
     */
195 1
    static public function getDomains($append = false)
0 ignored issues
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
196
    {
197 1
        $domains = Router::getInstance()->getDomains();
198 1
        if ($append) {
199 1
            foreach ($domains as &$domain) {
200
                foreach ($domain as &$path) {
201
                    $path .= DIRECTORY_SEPARATOR;
202
                }
203
            }
204
        }
205 1
        return $domains;
206
    }
207
208
    /**
209
     * Método que añade todas las funciones de las plantillas
210
     */
211 1
    private function addTemplateFunctions()
212
    {
213
        //Asignamos las funciones especiales
214
        $functions = [
215 1
            'asset' => TemplateFunctions::ASSETS_FUNCTION,
216 1
            'form' => TemplateFunctions::FORM_FUNCTION,
217 1
            'form_widget' => TemplateFunctions::WIDGET_FUNCTION,
218 1
            'form_button' => TemplateFunctions::BUTTON_FUNCTION,
219 1
            'get_config' => TemplateFunctions::CONFIG_FUNCTION,
220 1
            'path' => TemplateFunctions::ROUTE_FUNCTION,
221 1
            'resource' => TemplateFunctions::RESOURCE_FUNCTION,
222 1
            'session' => TemplateFunctions::SESSION_FUNCTION,
223 1
            'existsFlash' => TemplateFunctions::EXISTS_FLASH_FUNCTION,
224 1
            'getFlash' => TemplateFunctions::GET_FLASH_FUNCTION,
225 1
            'getQuery' => TemplateFunctions::GET_QUERY_FUNCTION,
226
        ];
227 1
        foreach($functions as $name => $function) {
228 1
            $this->addTemplateFunction($name, $function);
229
        }
230 1
    }
231
232
    /**
233
     * Método que devuelve el motod de plantillas
234
     * @return \Twig_Environment
235
     */
236 1
    public function getTemplateEngine()
237
    {
238 1
        return $this->tpl;
239
    }
240
241
    /**
242
     * Method that extract all domains for using them with the templates
243
     */
244 1
    private function loadDomains()
245
    {
246 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...
247 1
        if (null !== $domains) {
248 1
            foreach ($domains as $domain => $paths) {
249
                $this->addPath($paths['template'], preg_replace('/(@|\/)/', '', $domain));
250
            }
251
        }
252 1
    }
253
254
    /**
255
     * Método que inicializa el motor de plantillas
256
     */
257 1
    private function setup()
258
    {
259 1
        $loader = new \Twig_Loader_Filesystem(GeneratorHelper::getTemplatePath());
260 1
        $this->tpl = new \Twig_Environment($loader, array(
261 1
            'cache' => CACHE_DIR . DIRECTORY_SEPARATOR . 'twig',
262 1
            'debug' => (bool)$this->debug,
263 1
            'auto_reload' => Config::getParam('twig.autoreload', TRUE),
264
        ));
265 1
        $this->loadDomains();
266 1
    }
267
268
    /**
269
     * Método que inyecta los parseadores
270
     */
271 1
    private function addTemplateTokens()
272
    {
273
        //Añadimos las extensiones de los tags
274 1
        $this->tpl->addTokenParser(new AssetsTokenParser("css"));
275 1
        $this->tpl->addTokenParser(new AssetsTokenParser("js"));
276 1
    }
277
278
    /**
279
     * Método que inyecta las optimizaciones al motor de la plantilla
280
     */
281 1
    private function optimizeTemplates()
282
    {
283
        //Optimizamos
284 1
        $this->tpl->addExtension(new \Twig_Extensions_Extension_I18n());
285 1
    }
286
287
    /**
288
     * Method that extract all path tag for extracting translations
289
     * @param array $domains
290
     *
291
     * @return array
292
     */
293 1
    private function parsePathTranslations($domains)
294
    {
295 1
        $translations = array();
296 1
        if (!empty($domains)) {
297
            foreach ($domains as $domain => $paths) {
298
                if (strlen($domain) && array_key_exists("template", $paths)) {
299
                    $this->addPath($paths["template"], $domain);
300
                    $translations[] = $this->generateTemplate($paths["template"], $domain);
301
                }
302
            }
303
        }
304
305 1
        return $translations;
306
    }
307
308
    /**
309
     * Method that generate all template caches
310
     */
311 1
    private function generateTemplatesCache()
312
    {
313
        /** @var \Twig_Loader_Filesystem $loader */
314 1
        $loader = $this->tpl->getLoader();
315 1
        $availablePaths = $loader->getPaths();
316 1
        if (!empty($availablePaths)) {
317 1
            foreach ($availablePaths as $path) {
318 1
                $this->generateTemplate($path);
319
            }
320
        }
321 1
    }
322
}
323