Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
80.36% covered (warning)
80.36%
45 / 56
80.00% covered (warning)
80.00%
12 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 1
Head
80.36% covered (warning)
80.36%
45 / 56
80.00% covered (warning)
80.00%
12 / 15
44.28
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addAsset
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 addTag
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setLanguage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLanguage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 render
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 renderStyle
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 renderScript
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 setStyle
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
 setScript
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
 getStyleAll
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getScriptAll
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 renderAssets
82.35% covered (warning)
82.35%
14 / 17
0.00% covered (danger)
0.00%
0 / 1
8.35
 renderAssetsLate
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 renderTags
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   phpOMS\Model\Html
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\Model\Html;
16
17use phpOMS\Asset\AssetType;
18use phpOMS\Contract\RenderableInterface;
19use phpOMS\Localization\ISO639x1Enum;
20
21/**
22 * Head class.
23 *
24 * Responsible for handling everything that's going on in the <head>
25 *
26 * @package phpOMS\Model\Html
27 * @license OMS License 2.0
28 * @link    https://jingga.app
29 * @since   1.0.0
30 */
31final class Head implements RenderableInterface
32{
33    /**
34     * Page language.
35     *
36     * @var string
37     * @since 1.0.0
38     */
39    private string $language = ISO639x1Enum::_EN;
40
41    /**
42     * Page title.
43     *
44     * @var string
45     * @since 1.0.0
46     */
47    public string $title = '';
48
49    /**
50     * Assets bound to this page instance.
51     *
52     * @var array|array<string, array{type:int, attributes:array}>
53     * @since 1.0.0
54     */
55    private array $assets = [];
56
57    /**
58     * Page meta.
59     *
60     * @var Meta
61     * @since 1.0.0
62     */
63    public Meta $meta;
64
65    /**
66     * html style.
67     *
68     * Inline style
69     *
70     * @var mixed[]
71     * @since 1.0.0
72     */
73    private array $style = [];
74
75    /**
76     * html script.
77     *
78     * @var mixed[]
79     * @since 1.0.0
80     */
81    private array $script = [];
82
83    /**
84     * Tags bound to this page instance.
85     *
86     * @var array
87     * @since 1.0.0
88     */
89    private array $tags = [];
90
91    /**
92     * Constructor.
93     *
94     * @since 1.0.0
95     */
96    public function __construct()
97    {
98        $this->meta = new Meta();
99    }
100
101    /**
102     * Add asset.
103     *
104     * @param int    $type       Asset type
105     * @param string $uri        Asset uri
106     * @param array  $attributes Asset attributes
107     *
108     * @return void
109     *
110     * @since 1.0.0
111     */
112    public function addAsset(int $type, string $uri, array $attributes = []) : void
113    {
114        $this->assets[$uri] = ['type' => $type, 'attributes' => $attributes];
115    }
116
117    /**
118     * Add tag.
119     *
120     * @param string $tag        Html tag type
121     * @param string $content    Tag content
122     * @param array  $attributes Tag attributes
123     *
124     * @return void
125     *
126     * @since 1.0.0
127     */
128    public function addTag(string $tag, string $content, array $attributes = []) : void
129    {
130        $this->tags[] = ['tag' => $tag, 'content' => $content, 'attributes' => $attributes];
131    }
132
133    /**
134     * Set page language.
135     *
136     * @param string $language language string
137     *
138     * @return void
139     *
140     * @since 1.0.0
141     */
142    public function setLanguage(string $language) : void
143    {
144        $this->language = $language;
145    }
146
147    /**
148     * Get page language.
149     *
150     * @return string
151     *
152     * @since 1.0.0
153     */
154    public function getLanguage() : string
155    {
156        return $this->language;
157    }
158
159    /**
160     * Get the evaluated contents of the object.
161     *
162     * @param mixed ...$data Data to pass to renderer
163     *
164     * @return string
165     *
166     * @since 1.0.0
167     */
168    public function render(mixed ...$data) : string
169    {
170        $head  = '';
171        $head .= $this->meta->render();
172        $head .= $this->renderAssets();
173        $head .= empty($this->style) ? '' : '<style>' . $this->renderStyle() . '</style>';
174
175        return $head . (empty($this->script) ? '' : '<script>' . $this->renderScript() . '</script>');
176    }
177
178    /**
179     * Render style.
180     *
181     * @return string
182     *
183     * @since 1.0.0
184     */
185    public function renderStyle() : string
186    {
187        $style = '';
188        foreach ($this->style as $css) {
189            $style .= $css;
190        }
191
192        return $style;
193    }
194
195    /**
196     * Render script.
197     *
198     * @return string
199     *
200     * @since 1.0.0
201     */
202    public function renderScript() : string
203    {
204        $script = '';
205        foreach ($this->script as $js) {
206            $script .= $js;
207        }
208
209        return $script;
210    }
211
212    /**
213     * Set a style.
214     *
215     * @param string $key       Style key
216     * @param string $style     Style source
217     * @param bool   $overwrite Overwrite if already existing
218     *
219     * @return void
220     *
221     * @since 1.0.0
222     */
223    public function setStyle(string $key, string $style, bool $overwrite = true) : void
224    {
225        if ($overwrite || !isset($this->script[$key])) {
226            $this->style[$key] = $style;
227        }
228    }
229
230    /**
231     * Set a script.
232     *
233     * @param string $key       Script key
234     * @param string $script    Script source
235     * @param bool   $overwrite Overwrite if already existing
236     *
237     * @return void
238     *
239     * @since 1.0.0
240     */
241    public function setScript(string $key, string $script, bool $overwrite = true) : void
242    {
243        if ($overwrite || !isset($this->script[$key])) {
244            $this->script[$key] = $script;
245        }
246    }
247
248    /**
249     * Get all styles.
250     *
251     * @return array
252     *
253     * @since 1.0.0
254     */
255    public function getStyleAll() : array
256    {
257        return $this->style;
258    }
259
260    /**
261     * Get all scripts.
262     *
263     * @return array
264     *
265     * @since 1.0.0
266     */
267    public function getScriptAll() : array
268    {
269        return $this->script;
270    }
271
272    /**
273     * Render assets.
274     *
275     * @return string
276     *
277     * @since 1.0.0
278     */
279    public function renderAssets() : string
280    {
281        $rendered = '';
282        foreach ($this->assets as $uri => $asset) {
283            if ($asset['type'] === AssetType::CSS) {
284                $rendered .= '<link rel="stylesheet" type="text/css" href="' . $uri . '"';
285
286                foreach ($asset['attributes'] as $key => $attribute) {
287                    $rendered .= \is_string($key)
288                        ? ' ' . $key . '="' . $attribute . '"'
289                        : ' ' . $attribute;
290                }
291
292                $rendered .= '>';
293            } elseif ($asset['type'] === AssetType::JS) {
294                $rendered .= '<script src="' . $uri . '"';
295
296                foreach ($asset['attributes'] as $key => $attribute) {
297                    $rendered .= \is_string($key)
298                        ? ' ' . $key . '="' . $attribute . '"'
299                        : ' ' . $attribute;
300                }
301
302                $rendered .= '></script>';
303            }
304        }
305
306        return $rendered;
307    }
308
309    /**
310     * Render assets.
311     *
312     * @return string
313     *
314     * @since 1.0.0
315     */
316    public function renderAssetsLate() : string
317    {
318        $rendered = '';
319        foreach ($this->assets as $uri => $asset) {
320            if ($asset['type'] === AssetType::JSLATE) {
321                $rendered .= '<script src="' . $uri . '"';
322
323                foreach ($asset['attributes'] as $key => $attribute) {
324                    $rendered .= ' ' . $key . '="' . $attribute . '"';
325                }
326
327                $rendered .= '></script>';
328            }
329        }
330
331        return $rendered;
332    }
333
334    /**
335     * Render tags.
336     *
337     * @return string
338     *
339     * @since 1.0.0
340     */
341    public function renderTags() : string
342    {
343        $rendered = '';
344        foreach ($this->tags as $tag) {
345            $rendered .= '<' . $tag['tag'];
346
347            foreach ($tag['attributes'] as $key => $attribute) {
348                $rendered .= ' ' . $key . '="' . $attribute . '"';
349            }
350
351            $rendered .= '>' . $tag['content'] . '</' . $tag['tag'] . '>';
352        }
353
354        return $rendered;
355    }
356}