Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
87.04% covered (warning)
87.04%
47 / 54
73.33% covered (warning)
73.33%
11 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 1
ViewAbstract
87.04% covered (warning)
87.04%
47 / 54
73.33% covered (warning)
73.33%
11 / 15
38.82
0.00% covered (danger)
0.00%
0 / 1
 getTemplate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setTemplate
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 printHtml
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 html
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 printCli
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 cli
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
 getViews
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getView
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 removeView
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 addView
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 serialize
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 toArray
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 render
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 renderTemplate
83.33% covered (warning)
83.33%
15 / 18
0.00% covered (danger)
0.00%
0 / 1
8.30
 build
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
3.14
 unserialize
n/a
0 / 0
n/a
0 / 0
1
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   phpOMS\Views
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace phpOMS\Views;
16
17use phpOMS\Contract\RenderableInterface;
18
19/**
20 * View Abstract.
21 *
22 * @package phpOMS\Views
23 * @license OMS License 2.0
24 * @link    https://jingga.app
25 * @since   1.0.0
26 */
27abstract class ViewAbstract implements RenderableInterface
28{
29    /**
30     * Base path.
31     *
32     * @var string
33     * @since 1.0.0
34     */
35    protected const BASE_PATH = __DIR__ . '/../..';
36
37    /**
38     * Output is buffered
39     *
40     * @var bool
41     * @since 1.0.0
42     */
43    public bool $isBuffered = true;
44
45    /**
46     * Template.
47     *
48     * @var string
49     * @since 1.0.0
50     */
51    protected string $template = '';
52
53    /**
54     * Views.
55     *
56     * @var \phpOMS\Views\View[]
57     * @since 1.0.0
58     */
59    protected array $views = [];
60
61    /**
62     * Get the template.
63     *
64     * @return string
65     *
66     * @since 1.0.0
67     */
68    public function getTemplate() : string
69    {
70        return $this->template;
71    }
72
73    /**
74     * Set the template.
75     *
76     * @param string $template  View template
77     * @param string $extension Extension of the template
78     *
79     * @return void
80     *
81     * @since 1.0.0
82     */
83    public function setTemplate(string $template, string $extension = 'tpl.php') : void
84    {
85        $this->template = self::BASE_PATH . $template . '.' . $extension;
86    }
87
88    /**
89     * Print html output.
90     *
91     * @param ?string $text Text
92     *
93     * @return string
94     *
95     * @since 1.0.0
96     */
97    public function printHtml(?string $text) : string
98    {
99        return $text === null ? '' : \htmlspecialchars($text);
100    }
101
102    /**
103     * Print html output.
104     *
105     * @param ?string $text Text
106     *
107     * @return string
108     *
109     * @since 1.0.0
110     */
111    public static function html(?string $text) : string
112    {
113        return $text === null ? '' : \htmlspecialchars($text);
114    }
115
116    /**
117     * Print cli output.
118     *
119     * @param ?string $text Text
120     *
121     * @return string
122     *
123     * @since 1.0.0
124     */
125    public function printCli(?string $text) : string
126    {
127        return $text === null ? '' : \escapeshellcmd($text);
128    }
129
130    /**
131     * Print cli output.
132     *
133     * @param ?string $text Text
134     *
135     * @return string
136     *
137     * @since 1.0.0
138     */
139    public static function cli(?string $text) : string
140    {
141        return $text === null ? '' : \escapeshellcmd($text);
142    }
143
144    /**
145     * Returns all views
146     *
147     * @return View[]
148     *
149     * @since 1.0.0
150     */
151    public function getViews() : array
152    {
153        return $this->views;
154    }
155
156    /**
157     * Returns a specific view
158     *
159     * @param string $id View ID
160     *
161     * @return false|self
162     *
163     * @since 1.0.0
164     */
165    public function getView(string $id) : bool | self
166    {
167        if (!isset($this->views[$id])) {
168            return false;
169        }
170
171        return $this->views[$id];
172    }
173
174    /**
175     * Remove view bz id
176     *
177     * @param string $id View ID
178     *
179     * @return bool
180     *
181     * @since 1.0.0
182     */
183    public function removeView(string $id) : bool
184    {
185        if (isset($this->views[$id])) {
186            unset($this->views[$id]);
187
188            return true;
189        }
190
191        return false;
192    }
193
194    /**
195     * Add view.
196     *
197     * @param string $id        View ID
198     * @param View   $view      View to add
199     * @param bool   $overwrite Overwrite existing view
200     *
201     * @return bool
202     *
203     * @since 1.0.0
204     */
205    public function addView(string $id, View $view, bool $overwrite = false) : bool
206    {
207        if ($overwrite || !isset($this->views[$id])) {
208            $this->views[$id] = $view;
209
210            return true;
211        }
212
213        return false;
214    }
215
216    /**
217     * Serialize view for rendering.
218     *
219     * @return string
220     *
221     * @since 1.0.0
222     */
223    public function serialize() : string
224    {
225        if (empty($this->template)) {
226            return (string) \json_encode($this->toArray());
227        }
228
229        return $this->render();
230    }
231
232    /**
233     * Arrayify view and it's subviews.
234     *
235     * @return array
236     *
237     * @since 1.0.0
238     */
239    public function toArray() : array
240    {
241        $viewArray = [];
242
243        if ($this->template !== '') {
244            $viewArray[] = $this->render();
245        }
246
247        foreach ($this->views as $key => $view) {
248            $viewArray[$key] = $view->toArray();
249        }
250
251        return $viewArray;
252    }
253
254    /**
255     * Get view/template response.
256     *
257     * @param mixed ...$data Data to pass to renderer
258     *
259     * @return string
260     *
261     * @since 1.0.0
262     */
263    public function render(mixed ...$data) : string
264    {
265        return $this->renderTemplate($this->template, ...$data);
266    }
267
268    /**
269     * Render a template file
270     *
271     * @param string $template Template path
272     * @param mixed  ...$data  Data to pass to renderer
273     *
274     * @return string
275     *
276     * @since 1.0.0
277     */
278    protected function renderTemplate(string $template, mixed ...$data) : string
279    {
280        $obLevel = 0;
281        $ob      = '';
282
283        try {
284            $path = $template;
285            if (!\is_file($path)) {
286                return '';
287            }
288
289            if ($this->isBuffered) {
290                ++$obLevel;
291                \ob_start();
292            }
293
294            /** @noinspection PhpIncludeInspection */
295            $includeData = include $path;
296
297            if ($this->isBuffered) {
298                --$obLevel;
299                $ob .= (string) \ob_get_clean();
300            }
301
302            if (\is_array($includeData)) {
303                $ob .= (string) \json_encode($includeData);
304            }
305        } catch (\Throwable $_) {
306            if ($obLevel > 0 && $this->isBuffered) {
307                $ob .= (string) \ob_get_clean();
308            }
309        }
310
311        return $ob;
312    }
313
314    /**
315     * Very similar to render, except that it executes the template file and returns its response as is.
316     * This allows to build the template as any datatype (e.g. pdf).
317     *
318     * @param mixed ...$data Data to pass to build
319     *
320     * @return mixed
321     *
322     * @since 1.0.0
323     */
324    public function build(mixed ...$data) : mixed
325    {
326        $ob = '';
327
328        try {
329            $path = $this->template;
330            if (!\is_file($path)) {
331                return '';
332            }
333
334            /** @noinspection PhpIncludeInspection */
335            $ob = include $path;
336        } catch (\Throwable $_) {
337            $ob = '';
338        }
339
340        return $ob;
341    }
342
343    /**
344     * Unserialize view.
345     *
346     * @param string $raw Raw data to parse
347     *
348     * @return void
349     *
350     * @since 1.0.0
351     * @codeCoverageIgnore
352     */
353    public function unserialize(mixed $raw) : void
354    {
355    }
356}