Test Failed
Push — main ( a8a1f8...d105a1 )
by Rafael
11:47
created

Render::setSkin()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 2
nop 1
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Copyright (C) 2022-2023  Rafael San José Tovar   <[email protected]>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
namespace Alxarafe\Core\Singletons;
20
21
use DebugBar\DebugBarException;
22
use Twig\Environment;
23
use Twig\Error\LoaderError;
24
use Twig\Error\RuntimeError;
25
use Twig\Error\SyntaxError;
26
use Twig\Loader\FilesystemLoader;
27
28
/**
29
 * Class Skin
30
 *
31
 * @package Alxarafe\Helpers
32
 */
33
class Render
34
{
35
36
    /**
37
     * The skins folder contains any folder for each skin, which defines the css, js, html files and images that
38
     * provide a visual aspect to the application.
39
     */
40
    const SKINS_FOLDER = '/html/skins';
41
42
    /**
43
     * The common folder basically contains the html and js files that provide the operation of the page, they
44
     * could be supported by other files of the skin, to modify the visual aspect.
45
     *
46
     * The system search any file in the skin, and if it not exists, search it in common.
47
     */
48
    const COMMON_FOLDER = '/html/common';
49
50
    /**
51
     * It is the name of the template that is being used.
52
     *
53
     * The template is the name of the file to load. It will be searched first in the skin, and if it is not
54
     * found, then in common.
55
     *
56
     * First, search SKIN_FOLDER + $currentSkin + $currentTemplate
57
     * If not found, seach in COMMON_FOLDER + $currentTemplate
58
     *
59
     * @var string
60
     */
61
    private static string $currentTemplate;
62
63
    /**
64
     * It is the name of the skin that is being used.
65
     *
66
     * The files are searched first in SKIN_FOLDER + $currentSkin
67
     *
68
     * @var string
69
     */
70
    private static string $currentSkin;
71
72
    /**
73
     * It is the skin, that is, the folder that contains the templates.
74
     *
75
     * Es el nombre del fichero que contiene las plantillas del tema.
76
     * Será el primer lugar donde se buscará $currentTemplate.
77
     *
78
     * It is the folder where the different skins are located. Each skin uses a
79
     * folder defined by $template, which contains the templates that will be used.
80
     *
81
     * @var string
82
     */
83
    private static string $templatesFolder;
84
85
    private $debug;
0 ignored issues
show
introduced by
The private property $debug is not used, and could be removed.
Loading history...
86
87
    public function __construct(string $index = 'main')
0 ignored issues
show
Unused Code introduced by
The parameter $index is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

87
    public function __construct(/** @scrutinizer ignore-unused */ string $index = 'main')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
88
    {
89
        self::setSkin('default');
90
    }
91
92
    /**
93
     * Return the templates folder
94
     *
95
     * @return bool
96
     * @deprecated ¿In use?
97
     */
98
    public static function hasTemplatesFolder(): bool
99
    {
100
        return (self::$templatesFolder != null);
101
    }
102
103
    /**
104
     * TODO: Undocumented
105
     *
106
     * @return bool
107
     */
108
    public static function hasTemplate(): bool
109
    {
110
        return (self::$currentTemplate != null);
111
    }
112
113
    /**
114
     * Returns an array with the available skins.
115
     *
116
     * @return array
117
     */
118
    public function getSkins(): array
119
    {
120
        $path = BASE_FOLDER . self::SKINS_FOLDER;
121
        if (!is_dir($path)) {
122
            FlashMessages::setError("Directory '$path' does not exists!");
123
            return [];
124
        }
125
        $skins = scandir($path);
126
        $ret = [];
127
        foreach ($skins as $skin) {
128
            if ($skin != '.' && $skin != '..') {
129
                $ret[] = $skin;
130
            }
131
        }
132
        return $ret;
133
    }
134
135
    /**
136
     * TODO: Undocumented
137
     */
138
    public static function setSkin($skin)
139
    {
140
        if (!isset(self::$currentSkin) || self::$currentSkin !== $skin) {
141
            self::$currentSkin = $skin;
142
            self::setTemplatesFolder($skin);
143
            Debug::addMessage('messages', "Setting '$skin' skin");
144
        }
145
    }
146
147
    /**
148
     * Establish a new template. The parameter must be only de template name, no the path!
149
     *
150
     * @param string $template
151
     */
152
    public static function setTemplatesFolder(string $template)
153
    {
154
        self::$templatesFolder = self::SKINS_FOLDER . ('/' . trim($template, '/'));
155
        Debug::addMessage('messages', "Setting '" . self::$templatesFolder . "' templates folder");
156
    }
157
158
    /**
159
     * TODO: Undocumented
160
     *
161
     * @param $template
162
     *
163
     * @throws DebugBarException
164
     */
165
    public static function setTemplate($template)
166
    {
167
        self::$currentTemplate = $template;
168
        Debug::addMessage('messages', "Setting '$template' template");
169
    }
170
171
    /**
172
     * TODO: Undocumented
173
     *
174
     * @param array $vars
175
     *
176
     * @return string
177
     * @throws DebugBarException
178
     */
179
    public static function render(array $vars): string
180
    {
181
        Debug::addMessage('messages', 'Templates folder: ' . self::$templatesFolder);
182
        Debug::addMessage('messages', 'Current template: ' . self::$currentTemplate);
183
184
        return self::renderIt($vars);
185
    }
186
187
    /**
188
     * TODO: Undocumented
189
     *
190
     * @param array $vars
191
     *
192
     * @return string
193
     * @throws DebugBarException
194
     */
195
    private static function renderIt(array $vars): string
196
    {
197
        Debug::startTimer('render', 'Rendering time');
198
199
        $templateVars = array_merge($vars, [
200
            '_REQUEST' => $_REQUEST,
201
            '_GET' => $_GET,
202
            '_POST' => $_POST,
203
            'GLOBALS' => $GLOBALS,
204
        ]);
205
206
        $usePath = self::getPaths();
207
208
        Debug::addMessage('messages', 'Using:' . print_r($usePath, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($usePath, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

208
        Debug::addMessage('messages', 'Using:' . /** @scrutinizer ignore-type */ print_r($usePath, true));
Loading history...
209
210
        //                $loader = new Twig_Loader_Filesystem($usePath);
211
        $loader = new FilesystemLoader($usePath);
212
        // TODO: Would not it be better to use a random constant instead of twig.Twig?
213
        $options = defined('DEBUG') && DEBUG ? ['debug' => true] : ['cache' => (BASE_FOLDER ?? '') . '/tmp/twig.Twig'];
214
215
        //                $twig = new Twig_Environment($loader, $options);
216
        $twig = new Environment($loader, $options);
217
218
        $template = ($templateVars['template'] ?? self::$currentTemplate) . '.twig';
219
        Debug::addMessage('messages', "Using '$template' template");
220
        try {
221
            $return = $twig->render($template, $templateVars);
222
        } catch (LoaderError $e) {
223
            dump($e);
224
            die('LoaderError');
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
225
        } catch (RuntimeError $e) {
226
            dump($e);
227
            die('RuntimeError');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
228
        } catch (SyntaxError $e) {
229
            dump($e);
230
            die('SyntaxError');
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return string. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
231
        }
232
233
        //        Debug::stopTimer('render');
234
        return $return;
235
    }
236
237
    private static function getPaths(): array
238
    {
239
        // Only use really existing path
240
        $usePath = [];
241
        $paths = [
242
            BASE_FOLDER . self::SKINS_FOLDER,
243
            self::getTemplatesFolder(),
244
            self::getCommonTemplatesFolder(),
245
            //            DEFAULT_TEMPLATES_FOLDER,
246
            //            ALXARAFE_TEMPLATES_FOLDER,
247
        ];
248
        foreach ($paths as $path) {
249
            if (file_exists($path)) {
250
                $usePath[] = $path;
251
            }
252
        }
253
        return $usePath;
254
    }
255
256
    /**
257
     * TODO: Undocumented
258
     *
259
     * @return string
260
     */
261
    public static function getTemplatesFolder(): string
262
    {
263
        return constant('BASE_FOLDER') . self::$templatesFolder;
264
    }
265
266
    /**
267
     * TODO: Undocumented
268
     *
269
     * @return string
270
     */
271
    public static function getCommonTemplatesFolder(): string
272
    {
273
        return BASE_FOLDER . self::COMMON_FOLDER;
274
    }
275
276
    /**
277
     * ¿In use?
278
     *
279
     * @param string $string
280
     *
281
     * @return string
282
     */
283
    public function getResource(string $string): string
284
    {
285
        foreach ($this->getPathsUri() as $path) {
286
            if (file_exists($path['path'] . $string)) {
287
                Debug::addMessage('messages', 'Return: ' . $path['uri'] . $string);
288
                return $path['uri'] . $string;
289
            }
290
        }
291
292
        Debug::addMessage('messages', 'Not found: ' . $string);
293
        return $string;
294
    }
295
296
    /**
297
     * ¿In use?
298
     *
299
     * @return array
300
     */
301
    private function getPathsUri(): array
302
    {
303
        // Only use really existing path
304
        $usePath = [];
305
        if (file_exists($this->getTemplatesFolder())) {
306
            $usePath[] = ['path' => $this->getTemplatesFolder(), 'uri' => $this->getTemplatesUri()];
307
        }
308
        if (file_exists($this->getCommonTemplatesFolder())) {
309
            $usePath[] = ['path' => $this->getCommonTemplatesFolder(), 'uri' => $this->getCommonTemplatesUri()];
310
        }
311
        //        if (file_exists(DEFAULT_TEMPLATES_FOLDER)) {
312
        //            $usePath[] = ['path' => DEFAULT_TEMPLATES_FOLDER, 'uri' => DEFAULT_TEMPLATES_URI];
313
        //        }
314
        //        if (file_exists(ALXARAFE_TEMPLATES_FOLDER)) {
315
        //            $usePath[] = ['path' => ALXARAFE_TEMPLATES_FOLDER, 'uri' => ALXARAFE_TEMPLATES_URI];
316
        //        }
317
        return $usePath;
318
    }
319
320
    /**
321
     * Returns the URI of the templates folder.
322
     * Search any file, first at this location.
323
     *
324
     * @return string
325
     */
326
    public static function getTemplatesUri(): string
327
    {
328
        return BASE_URI . self::$templatesFolder;
329
    }
330
331
    /**
332
     * Returns the URI of the common templates folder.
333
     * If a file does not exist in templates folder, search it in this folder.
334
     *
335
     * @return string
336
     */
337
    public function getCommonTemplatesUri(): string
338
    {
339
        return BASE_URI . self::COMMON_FOLDER;
340
    }
341
}
342