Node::handleAsXhtml()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

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