Completed
Push — master ( 1474ca...abb884 )
by Jan-Petter
02:47
created

Render::__construct()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 28
rs 6.7272
cc 7
eloc 17
nc 7
nop 2
1
<?php
2
namespace vipnytt\OPMLParser;
3
4
use DOMDocument;
5
use SimpleXMLElement;
6
7
class Render
8
{
9
    /**
10
     * Encoding to use if not provided
11
     */
12
    const ENCODING_DEFAULT = 'UTF-8';
13
14
    /**
15
     * Optional <head> elements
16
     */
17
    const OPTIONAL_HEAD_ELEMENTS = [
18
        'title',
19
        'dateCreated',
20
        'dateModified',
21
        'ownerName',
22
        'ownerEmail',
23
        'ownerId',
24
        'docs',
25
        'expansionState',
26
        'vertScrollState',
27
        'windowTop',
28
        'windowLeft',
29
        'windowBottom',
30
        'windowRight'
31
    ];
32
33
    /**
34
     * OPML versions supported
35
     */
36
    const SUPPORTED_VERSIONS = [
37
        '2.0',
38
        '1.0'
39
    ];
40
41
    /**
42
     * Default OPML version to use, if none is set
43
     */
44
    const VERSION_DEFAULT = '2.0';
45
46
    /**
47
     * Version to use for the build
48
     * 2.0 - `text` attribute is required
49
     * 1.0 - for legacy support
50
     * @var bool
51
     */
52
    protected $version;
53
54
    /**
55
     * Rendered XML object
56
     * @var SimpleXMLElement
57
     */
58
    protected $object;
59
60
    /**
61
     * Constructor
62
     *
63
     * @param array $array is the array we want to render and must follow structure defined above
64
     * @param string $version '2.0' if `text` attribute is required, '1.0' for legacy
65
     * @throws Exceptions\RenderException
66
     */
67
    public function __construct($array, $version = self::VERSION_DEFAULT)
68
    {
69
        $this->version = $version;
0 ignored issues
show
Documentation Bug introduced by
The property $version was declared of type boolean, but $version is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
70
        if (!in_array($this->version, self::SUPPORTED_VERSIONS)) {
71
            throw new Exceptions\RenderException('OPML version `' . $this->version . '` not supported');
72
        }
73
        $opml = new SimpleXMLElement('<opml></opml>');
74
        $opml->addAttribute('version', (string)$this->version);
75
        // Create head element. It is optional but head element will exist in the final XML object.
76
        $head = $opml->addChild('head');
77
        if (isset($array['head'])) {
78
            foreach ($array['head'] as $key => $value) {
79
                if (in_array($key, self::OPTIONAL_HEAD_ELEMENTS, true)) {
80
                    $head->addChild($key, $value);
81
                }
82
            }
83
        }
84
        // Check body is set and contains at least one element
85
        if (!isset($array['body'])) {
86
            throw new Exceptions\RenderException('The body element is missing');
87
        }
88
        // Create outline elements
89
        $body = $opml->addChild('body');
90
        foreach ($array['body'] as $outline) {
91
            $this->render_outline($body, $outline);
92
        }
93
        $this->object = $opml;
94
    }
95
96
    /**
97
     * Create a XML outline object in a parent object.
98
     *
99
     * @param SimpleXMLElement $parent_elt is the parent object of current outline
100
     * @param array $outline array representing an outline object
101
     * @return void
102
     * @throws Exceptions\RenderException
103
     */
104
    protected function render_outline($parent_elt, $outline)
105
    {
106
        $outline_elt = $parent_elt->addChild('outline');
107
        $text_is_present = false;
108
        foreach ($outline as $key => $value) {
109
            // Only outlines can be an array and so we consider children are also outline elements.
110
            if ($key === '@outlines' && is_array($value)) {
111
                foreach ($value as $outline_child) {
112
                    $this->render_outline($outline_elt, $outline_child);
113
                }
114
            } elseif (is_array($value)) {
115
                throw new Exceptions\RenderException('Type of outline elements cannot be array: ' . $key);
116
            } else {
117
                // Detect text attribute is present, that's good :)
118
                if ($key === 'text') {
119
                    $text_is_present = true;
120
                }
121
122
                $outline_elt->addAttribute($key, $value);
123
            }
124
        }
125
        if (!$text_is_present && $this->version == '2.0') {
126
            throw new Exceptions\RenderException('The text element must be present for all outlines (applies to version 2.0 only)');
127
        }
128
    }
129
130
    /**
131
     * Return as a XML object
132
     *
133
     * @return SimpleXMLElement
134
     */
135
    public function asXMLObject()
136
    {
137
        return $this->object;
138
    }
139
140
    /**
141
     * Return as an OPML string
142
     *
143
     * @param string $encoding Character encoding
144
     * @return string
145
     */
146
    public function asString($encoding = self::ENCODING_DEFAULT)
147
    {
148
        $dom = new DOMDocument('1.0', $encoding);
149
        $dom->loadXML($this->object->asXML());
150
        $dom->encoding = $encoding;
151
        $dom->preserveWhiteSpace = false;
152
        return preg_replace("/\r\n|\n|\r/", '', $dom->saveXML());
153
    }
154
}
155