Completed
Push — master ( 3fe817...1a0e89 )
by Marko
02:46
created

AframeDOMDocument::appendFormatComment()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 7
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 2
crap 2
1
<?php
2
/** @formatter:off
3
 * ******************************************************************
4
 * Created by   Marko Kungla on Jun 27, 2016 - 9:55:09 PM
5
 * Contact      [email protected]
6
 * @copyright   2016 Marko Kungla - https://github.com/mkungla
7
 * @license     The MIT License (MIT)
8
 * 
9
 * @category       AframeVR
10
 * @package        aframe-php
11
 * 
12
 * Lang         PHP (php version >= 7)
13
 * Encoding     UTF-8
14
 * File         AframeDOMDocument.php
15
 * Code format  PSR-2 and 12
16
 * @link        https://github.com/mkungla/aframe-php
17
 ^ @issues      https://github.com/mkungla/aframe-php/issues
18
 * ********************************************************************
19
 * Contributors:
20
 * @author Marko Kungla <[email protected]>
21
 * ********************************************************************
22
 * Comments:
23
 * @formatter:on */
24
namespace AframeVR\Core\DOM;
25
26
use \AframeVR\Core\Config;
27
use \DOMImplementation;
28
use \DOMDocumentType;
29
use \DOMDocument;
30
use \AframeVR\Core\Entity;
31
use \AframeVR\Interfaces\AssetsInterface;
32
33
final class AframeDOMDocument extends DOMImplementation
34
{
35
36
    const DEFAULT_METATAGS = array(
37
        array(
38
            'charset' => 'utf-8'
39
        ),
40
        array(
41
            'name' => 'viewport',
42
            'content' => 'width=device-width,initial-scale=1,maximum-scale=1,shrink-to-fit=no,user-scalable=no,minimal-ui'
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 122 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...
43
        ),
44
        array(
45
            'name' => 'mobile-web-app-capable',
46
            'content' => 'yes'
47
        ),
48
        array(
49
            'name' => 'theme-color',
50
            'content' => 'black'
51
        )
52
    );
53
54
    /**
55
     * A-Frame DOM Document type
56
     *
57
     * @var \DOMDocumentType
58
     */
59
    protected $doctypeObj;
60
61
    /**
62
     * A-Frame DOM Document
63
     *
64
     * @var \DOMDocument
65
     */
66
    protected $docObj;
67
68
    /**
69
     * Scene meta tile
70
     *
71
     * @var string $scene_title
72
     */
73
    protected $scene_title = 'Untitled';
74
75
    /**
76
     * Scene meta description
77
     *
78
     * @var string $scene_description
79
     */
80
    protected $scene_description = '';
81
82
    /**
83
     * CDN Of aframe.js
84
     *
85
     * @var string
86
     */
87
    protected $aframe_cdn;
88
89
    /**
90
     * Whether to use CDN
91
     *
92
     * @var bool $use_cdn
93
     */
94
    protected $use_cdn = false;
95
96
    /**
97
     * <head>
98
     *
99
     * @var \DOMElement
100
     */
101
    protected $head;
102
103
    /**
104
     * <body>
105
     *
106
     * @var \DOMElement
107
     */
108
    protected $body;
109
110
    /**
111
     * <a-scene>
112
     *
113
     * @var \DOMElement
114
     */
115
    protected $scene;
116
117
    /**
118
     * <a-assets>
119
     *
120
     * @var \DOMElement
121
     */
122
    protected $assets;
123
124
    /**
125
     * Nicely formats output with indentation and extra space.
126
     *
127
     * @var bool
128
     */
129
    protected $formatOutput = false;
130
131
    /**
132
     * A-Frame DOM
133
     *
134
     * @param Config $config            
135
     */
136 71
    public function __construct(Config $config)
137
    {
138
        /* Config */
139 71
        $this->formatOutput = is_bool($config->get('formatOutput')) ? $config->get('formatOutput') : false;
140 71
        $this->use_cdn = is_bool($config->get('useCDN')) ? $config->get('useCDN') : false;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 6 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
141
        
142
        /* Create HTML5 Document type */
143 71
        $this->createDocType('html');
144
        /* Create A-Frame DOM Document */
145 71
        $this->createAframeDocument();
146
       
147 71
        $this->documentBootstrap();
148
149
        /* Set CDN of aframe.js */
150 71
        $this->setCDN(is_string($config->get('CDN')) ? $config->get('CDN') : '');
151 71
    }
152
153
    /**
154
     * Set CDN for aframe.js or min.js
155
     *
156
     * @param string $cdn            
157
     * @return void
158
     */
159 71
    public function setCDN(string $cdn)
160
    {
161 71
        $this->aframe_cdn = $cdn;
162 71
    }
163
164
    /**
165
     * Render scene this DOM Object is attached to
166
     *
167
     * @return string
168
     */
169 5
    public function render(): string
170
    {
171 5
        $this->docObj->formatOutput = $this->formatOutput;
172 5
        $html = $this->docObj->getElementsByTagName('html')->item(0);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 23 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
173
        /* Make sure we do not add duplicates when render is called multiple times */
174 5
        if (! $html->hasChildNodes()) {
175 5
            $this->renderHead();
176 5
            $html->appendChild($this->head);
177
            
178 5
            $this->renderBody();
179 5
            $html->appendChild($this->body);
180
        }
181 5
        return $this->formatOutput ? $this->correctOutputFormat($this->docObj->saveHTML()) : $this->docObj->saveHTML();
182
    }
183
184
    /**
185
     * Set Scene meta title
186
     *
187
     * @param string $title            
188
     */
189 7
    public function setTitle(string $title)
190
    {
191 7
        $this->scene_title = $title;
192 7
    }
193
194
    /**
195
     * Set Scene meta description
196
     *
197
     * @param string $description            
198
     */
199 7
    public function setDescription(string $description)
200
    {
201 7
        $this->scene_description = $description;
202 7
    }
203
204
    /**
205
     * Append entities
206
     *
207
     * @param array $entities            
208
     * @return void
209
     */
210 7
    public function appendEntities(array $entities)
211
    {
212 7
        if (! empty($entities)) {
213 2
            foreach ($entities as $entity) {
214 2
                $this->appendEntity($entity);
215
            }
216
        }
217 7
    }
218
219
    /**
220
     * Append assets
221
     *
222
     * @param array $assets            
223
     * @return void
224
     */
225 2
    public function appendAssets(array $assets)
226
    {
227 2
        if (! empty($assets)) {
228 2
            if ($this->formatOutput) {
229 2
                $com = $this->docObj->createComment('');
230 2
                $this->scene->appendChild($com);
231
            }
232 2
            foreach ($assets as $asset) {
233 2
                $this->appendAsset($asset);
234
            }
235 2
            $this->scene->appendChild($this->assets);
236
        }
237 2
    }
238
239
    /**
240
     * Append asset
241
     *
242
     * Create asset DOMElement
243
     *
244
     * @param AssetsInterface $asset            
245
     */
246 2
    public function appendAsset(AssetsInterface $asset)
247
    {
248 2
        $this->appendFormatComment('assets', "\n\t");
249 2
        $this->assets->appendChild($asset->domElement($this->docObj));
250 2
    }
251
252
    /**
253
     * Create entity DOMElement
254
     *
255
     * Created entity and append it to scene
256
     *
257
     * @param Entity $entity            
258
     * @return void
259
     */
260 2
    public function appendEntity(Entity $entity)
261
    {
262 2
        $this->appendFormatComment('scene', "\n");
263 2
        $this->scene->appendChild($entity->domElement($this->docObj));
264 2
    }
265
266
    /**
267
     * Get HTML of Scene only
268
     *
269
     * @return string
270
     */
271 3
    public function renderSceneOnly()
272
    {
273 3
        $html = new DOMDocument();
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 15 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
274 3
        $html->formatOutput = $this->formatOutput;
275 3
        $html_scene = $html->importNode($this->scene, true);
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 9 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
276 3
        $html->appendChild($html_scene);
277 3
        return $this->formatOutput ? $this->correctOutputFormat($html->saveHTML()) : $html->saveHTML();
278
    }
279
280
    /**
281
     * Add document comment for formatting
282
     *
283
     * @param string $element            
284
     * @param string $comment            
285
     */
286 4
    protected function appendFormatComment(string $element, string $comment)
287
    {
288 4
        if ($this->formatOutput) {
289 4
            $com = $this->docObj->createComment($comment);
290 4
            $this->{$element}->appendChild($com);
291
        }
292 4
    }
293
294
    /**
295
     * Correct html format for tags which are not supported by DOMDocument
296
     *
297
     * @param string $html            
298
     * @return string
299
     */
300 4
    protected function correctOutputFormat($html)
301
    {
302
        $tags = array(
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
303 4
            '<!--',
304
            '-->',
305
            '<a-assets>',
306
            '</a-assets>',
307
            '</a-scene>'
308
        );
309
        $values = array(
310 4
            '',
311
            "\t",
312
            "\n\t<a-assets>",
313
            "\n\t</a-assets>",
314
            "\n</a-scene>"
315
        );
316 4
        return str_ireplace($tags, $values, $html);
317
    }
318
319
    /**
320
     * Prepeare head
321
     *
322
     * @return void
323
     */
324 5
    protected function renderHead()
325
    {
326 5
        $title = $this->docObj->createElement('title', $this->scene_title);
327 5
        $this->head->appendChild($title);
328 5
        $this->appendDefaultMetaTags();
329 5
        $this->appendCDN();
330 5
    }
331
332
    /**
333
     * Append deffault metatags
334
     *
335
     * @return void
336
     */
337 5
    protected function appendDefaultMetaTags()
338
    {
339 5
        $this->appendMetaTag(array(
340 5
            'name' => 'description',
341 5
            'content' => $this->scene_description
342
        ));
343 5
        foreach ($this->getDefaultMetaTags() as $tag)
344 5
            $this->appendMetaTag($tag);
345 5
    }
346
347
    /**
348
     * Get default meta tags
349
     *
350
     * @return array
351
     */
352 5
    protected function getDefaultMetaTags(): array
353
    {
354 5
        return self::DEFAULT_METATAGS;
355
    }
356
357
    /**
358
     * If requested by user use aframe CDN
359
     *
360
     * @return void
361
     */
362 5
    protected function appendCDN()
363
    {
364 5
        if ($this->use_cdn) {
365 3
            $cdn_script = $this->docObj->createElement('script');
366 3
            $cdn_script->setAttribute('src', $this->aframe_cdn);
367 3
            $this->head->appendChild($cdn_script);
368
        }
369 5
    }
370
371
    /**
372
     * Prepare body
373
     *
374
     * @return void
375
     */
376 5
    protected function renderBody()
377
    {
378 5
        $this->body->appendChild($this->scene);
379 5
    }
380
381
    /**
382
     * Create meta tags
383
     *
384
     * @param array $attr            
385
     */
386 5
    protected function appendMetaTag(array $attr)
387
    {
388 5
        $metatag = $this->docObj->createElement('meta');
389 5
        foreach ($attr as $key => $val)
390 5
            $metatag->setAttribute($key, $val);
391 5
        $this->head->appendChild($metatag);
392 5
    }
393
394
    /**
395
     * Creates an empty DOMDocumentType object
396
     *
397
     * @param string $doctype            
398
     * @return void
399
     */
400 71
    protected function createDocType(string $doctype)
401
    {
402 71
        $this->doctypeObj = $this->createDocumentType($doctype);
403 71
    }
404
405
    /**
406
     * Creates a DOMDocument object of the specified type with its document element
407
     *
408
     * @return void
409
     */
410 71
    protected function createAframeDocument()
411
    {
412 71
        $this->docObj = $this->createDocument(null, 'html', $this->doctypeObj);
413 71
    }
414
    
415
    /**
416
     * Create dom elements for DOMDocument
417
     * 
418
     * @return void
419
     */
420 71
    protected function documentBootstrap()
421
    {
422
        /* Create <head> element */
423 71
        $this->head = $this->docObj->createElement('head');
424
        /* Create <body> element */
425 71
        $this->body = $this->docObj->createElement('body', $this->formatOutput ? "\n" : '');
426
        /* Create <a-scene> element */
427 71
        $this->scene = $this->docObj->createElement('a-scene');
428
        /* Create <a-assets> element */
429 71
        $this->assets = $this->docObj->createElement('a-assets');
430 71
    }
431
}
432