Passed
Push — master ( 465c1d...3a012d )
by Ryan
03:02
created

Node   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 284
Duplicated Lines 0 %

Test Coverage

Coverage 90.48%

Importance

Changes 0
Metric Value
dl 0
loc 284
ccs 76
cts 84
cp 0.9048
rs 8.3999
c 0
b 0
f 0
wmc 38

16 Methods

Rating   Name   Duplication   Size   Complexity  
A getNode() 0 3 1
A handleAsText() 0 4 1
A handleAsXhtml() 0 14 1
A getAlias() 0 8 2
A getValue() 0 3 1
A getHandler() 0 4 1
A __toString() 0 3 1
A getBase() 0 3 1
A factory() 0 4 1
A handleAsSource() 0 4 1
A handleAsHtml() 0 4 1
A handleFallback() 0 8 3
D __construct() 0 48 20
A getSerialization() 0 3 1
A getLang() 0 3 1
A handleAsBase64() 0 4 1
1
<?php
2
/**
3
 * Copyright (c) 2017–2018 Ryan Parman <http://ryanparman.com>.
4
 * Copyright (c) 2017–2018 Contributors.
5
 *
6
 * http://opensource.org/licenses/Apache2.0
7
 */
8
9
declare(strict_types=1);
10
11
namespace SimplePie\Type;
12
13
use DOMAttr;
14
use DOMNode;
15
use DOMText;
16
use SimplePie\Enum\CharacterSet;
17
use SimplePie\Enum\Serialization;
18
use SimplePie\Exception\SimplePieException;
19
20
/**
21
 * A type model for a deep-level Node element.
22
 */
23
class Node extends AbstractType implements NodeInterface, TypeInterface
24
{
25
    /**
26
     * The raw `DOMNode` element.
27
     *
28
     * @var DOMNode|null
29
     */
30
    protected $node;
31
32
    /**
33
     * The content of the node, serialized appropriately.
34
     *
35
     * @var string|null
36
     */
37
    protected $value;
38
39
    /**
40
     * The language of the content.
41
     *
42
     * @var string|null
43
     */
44
    protected $lang;
45
46
    /**
47
     * The xml:base value of the content.
48
     *
49
     * @var string|null
50
     */
51
    protected $base;
52
53
    /**
54
     * The serialization of the content.
55
     *
56
     * @var string
57
     */
58
    protected $serialization = Serialization::TEXT;
59
60
    /**
61
     * Get the text node in multiple formats.
62
     *
63
     * @param DOMNode|null $node     A `DOMNode` element to read properties from.
64
     * @param array        $fallback An array of attributes for default XML attributes. The default value is an
65
     *                               empty array.
66
     *
67
     * @phpcs:disable Generic.Metrics.CyclomaticComplexity.MaxExceeded
68
     */
69 490
    public function __construct(?DOMNode $node = null, array $fallback = [])
70
    {
71 490
        if ($node) {
72 490
            $this->node  = $node;
73 490
            $this->value = $node->nodeValue;
74
75
            // Set some default values
76 490
            $this->handleFallback($fallback);
77
78 490
            if (XML_ELEMENT_NODE === $node->nodeType && $node->attributes->length > 0) {
79 142
                foreach ($node->attributes as $attribute) {
80 142
                    if ('xml:base' === $attribute->nodeName) {
81 41
                        $this->base = $attribute->nodeValue;
82 142
                    } elseif ('xml:lang' === $attribute->nodeName) {
83 66
                        $this->lang = $attribute->nodeValue;
84 134
                    } elseif ('src' === $attribute->name) {
85 1
                        $this->handleAsSource($attribute);
86 133
                    } elseif (
87 12
                        'type' === $attribute->name && (
88 121
                            Serialization::TEXT === $attribute->value
89 53
                            || 'text/plain' === $attribute->value
90 108
                        )
91 27
                    ) {
92 81
                        $this->handleAsText($node, $attribute);
93 12
                    } elseif (
94
                        'type' === $attribute->name && (
95 69
                            Serialization::HTML === $attribute->value
96 142
                            || 'text/html' === $attribute->value
97
                        )
98
                    ) {
99
                        $this->handleAsHtml($node, $attribute);
100
                    } elseif (
101 490
                        'type' === $attribute->name && (
102
                            Serialization::XHTML === $attribute->value
103
                            || 'application/xhtml+xml' === $attribute->value
104
                            || 'application/xml' === $attribute->value
105
                        )
106
                    ) {
107
                        $this->handleAsXhtml($node, $attribute);
108
                    } elseif (
109
                        'type' === $attribute->name && (
110 476
                            'application/octet-stream' === $attribute->value
111
                        )
112 476
                    ) {
113
                        $this->handleAsBase64($node);
114
                    } else {
115
                        $this->serialization = Serialization::TEXT;
116
                        $this->value         = $node->nodeValue;
117
                    }
118
                }
119
            }
120
        }
121
    }
122 39
123
    // @phpcs:enable
124 39
125 39
    /**
126
     * Casting this Node element to a string with return the _value_ of the Node.
127
     *
128
     * @return string
129
     */
130
    public function __toString(): string
131
    {
132
        return $this->getValue() ?? '';
133
    }
134 490
135
    /**
136 490
     * Creates a new `Node` object from a string of text (such as from an XML attribute).
137
     *
138
     * @param string $value The string of text to convert to a `Node` object.
139
     *
140
     * @return Node
141
     */
142
    public static function factory(string $value): self
143
    {
144 482
        return new self(
145
            new DOMText($value)
146 482
        );
147
    }
148
149
    /**
150
     * Gets the raw `DOMNode` element.
151
     *
152
     * @return DOMNode|null
153
     */
154
    public function getNode(): ?DOMNode
155
    {
156 379
        return $this->node;
157
    }
158 379
159
    /**
160
     * Gets the content of the node, serialized appropriately.
161
     *
162
     * @return string|null
163
     */
164
    public function getValue(): ?string
165
    {
166 30
        return $this->value;
167
    }
168 30
169
    /**
170
     * Gets the serialization of the content.
171
     *
172
     * Will always be one of the enums from `SimplePie\Enum\Serialization`.
173
     *
174
     * @return string
175
     */
176 3
    public function getSerialization(): string
177
    {
178 3
        return $this->serialization;
179
    }
180
181
    /**
182
     * Gets the language of the content.
183
     *
184
     * @return string|null
185
     */
186
    public function getLang(): self
187
    {
188
        return self::factory($this->lang ?? '');
189
    }
190
191
    /**
192
     * Gets the xml:base of the content.
193
     *
194
     * @return string|null
195
     */
196
    public function getBase(): self
197
    {
198
        return self::factory($this->base ?? '');
199
    }
200
201
    /**
202
     * {@inheritdoc}
203
     */
204
    public function getAlias(string $nodeName): string
205
    {
206
        switch ($nodeName) {
207
            case 'language':
208
                return 'lang';
209
210 490
            default:
211
                return $nodeName;
212 490
        }
213 2
    }
214
215
    /**
216 490
     * {@inheritdoc}
217 64
     */
218
    public function getHandler(string $nodeName, array $args = []): self
219 490
    {
220
        throw new SimplePieException(
221
            $this->getUnresolvableMessage($nodeName)
222
        );
223
    }
224
225
    /**
226 1
     * Handle the default "fallback" state of certain properties.
227
     *
228 1
     * @param array $fallback An array of attributes for default XML attributes. The default value is an empty array.
229 1
     */
230 1
    private function handleFallback(array $fallback = []): void
231
    {
232
        if (isset($fallback['base'])) {
233
            $this->base = $fallback['base']->nodeValue;
234
        }
235
236
        if (isset($fallback['lang'])) {
237
            $this->lang = $fallback['lang']->nodeValue;
238 12
        }
239
    }
240 12
241 12
    /**
242 12
     * Handle the content as source.
243 12
     *
244 12
     * @param DOMAttr $attribute The DOMAttr element.
245
     */
246 12
    private function handleAsSource(DOMAttr $attribute): void
247
    {
248
        $this->serialization = Serialization::TEXT;
249
        $this->value         = $attribute->nodeValue;
250
    }
251
252
    /**
253
     * Handle the content as plain text.
254 53
     *
255
     * @param DOMNode $node      The DOMNode element.
256 53
     * @param DOMAttr $attribute The DOMAttr element.
257 53
     */
258 53
    private function handleAsText(DOMNode $node, DOMAttr $attribute): void
259 53
    {
260 53
        $this->serialization = $attribute->nodeValue;
261
        $this->value         = $node->nodeValue;
262 53
    }
263
264
    /**
265
     * Handle the content as HTML.
266
     *
267
     * @param DOMNode $node      The DOMNode element.
268
     * @param DOMAttr $attribute The DOMAttr element.
269
     */
270 27
    private function handleAsHtml(DOMNode $node, DOMAttr $attribute): void
271
    {
272 27
        $this->serialization = $attribute->nodeValue;
273
        $this->value         = $node->nodeValue;
274
    }
275 27
276 27
    /**
277 27
     * Handle the content as XHTML.
278 27
     *
279 27
     * @param DOMNode $node      The DOMNode element.
280
     * @param DOMAttr $attribute The DOMAttr element.
281
     */
282
    private function handleAsXhtml(DOMNode $node, DOMAttr $attribute): void
283 27
    {
284 27
        $this->serialization = $attribute->nodeValue;
285
286
        // We can't just grab the content. We need to stringify it, then remove the wrapper element.
287
        $content = \preg_replace(
288
            '/^<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">(.*)<\/div>$/ims',
289
            '$1',
290
            $node->ownerDocument->saveXML(
291 12
                $node->getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'div')[0]
292
            )
293 12
        );
294 12
295 12
        $this->value = \trim($content);
296
    }
297
298
    /**
299
     * Handle the content as Base64-encoded text.
300
     *
301
     * @param DOMNode $node The DOMNode element.
302
     */
303
    private function handleAsBase64(DOMNode $node): void
304
    {
305
        $this->serialization = Serialization::TEXT;
306
        $this->value         = \base64_decode(\trim($node->nodeValue), true);
307
    }
308
}
309