HtmlQueryNode   A
last analyzed

Complexity

Total Complexity 27

Size/Duplication

Total Lines 312
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 89
c 1
b 0
f 0
dl 0
loc 312
ccs 100
cts 100
cp 1
rs 10
wmc 27

16 Methods

Rating   Name   Duplication   Size   Complexity  
A wrapAll() 0 17 3
A prepend() 0 9 1
A append() 0 8 1
A unwrap() 0 3 1
A insertAfter() 0 5 1
A prependTo() 0 5 1
A wrapInner() 0 24 4
A replaceAll() 0 5 1
A before() 0 8 1
A unwrapSelf() 0 4 1
A newNode() 0 5 2
A insertBefore() 0 5 1
A wrap() 0 20 3
A replaceWith() 0 24 4
A after() 0 9 1
A appendTo() 0 5 1
1
<?php
2
3
namespace Sulao\HtmlQuery;
4
5
use DOMNode;
6
use DOMNodeList;
7
8
/**
9
 * Class HtmlQueryNode
10
 *
11
 * @package Sulao\HtmlQuery
12
 */
13
abstract class HtmlQueryNode extends HtmlQueryAttribute
14
{
15
    /**
16
     * Insert content or node(s) before each matched node.
17
     *
18
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
19
     *
20
     * @return static
21 3
     */
22
    public function before($content)
23 3
    {
24
        $content = $this->contentResolve($content);
25
26
        return $this->each(function (HtmlNode $node, $index) use ($content) {
27 3
            $content->each(function (DOMNode $newNode) use ($node, $index) {
28 3
                $newNode = $this->newNode($newNode, $index);
29 3
                $node->before($newNode);
30 3
            });
31
        });
32
    }
33
34
    /**
35
     * Insert every matched node before the target.
36
     *
37
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $selector
38
     *
39
     * @return static
40 1
     */
41
    public function insertBefore($selector)
42 1
    {
43
        $target = $this->targetResolve($selector);
44 1
45
        return $target->before($this);
46
    }
47
48
    /**
49
     * Insert content or node(s) after each matched node.
50
     *
51
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
52
     *
53
     * @return static
54 5
     */
55
    public function after($content)
56 5
    {
57
        $content = $this->contentResolve($content);
58
59
        return $this->each(function (HtmlNode $node, $index) use ($content) {
60 5
            $content->each(function (DOMNode $newNode) use ($node, $index) {
61 5
                $newNode = $this->newNode($newNode, $index);
62 5
                $node->after($newNode);
63 5
            }, true);
64
        });
65
    }
66
67
    /**
68
     * Insert every matched node after the target.
69
     *
70
     * @param string|DOMNode|DOMNode[]DOMNodeList|static $selector
71
     *
72
     * @return static
73 3
     */
74
    public function insertAfter($selector)
75 3
    {
76
        $target = $this->targetResolve($selector);
77 3
78
        return $target->after($this);
79
    }
80
81
    /**
82
     * Insert content or node(s) to the end of every matched node.
83
     *
84
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
85
     *
86
     * @return static
87 6
     */
88
    public function append($content)
89 6
    {
90
        $content = $this->contentResolve($content);
91
92
        return $this->each(function (HtmlNode $node, $index) use ($content) {
93 6
            $content->each(function (DOMNode $newNode) use ($node, $index) {
94 6
                $newNode = $this->newNode($newNode, $index);
95 6
                $node->append($newNode);
96 6
            });
97
        });
98
    }
99
100
    /**
101
     * Insert every matched node to the end of the target.
102
     *
103
     * @param string|DOMNode|DOMNode[]DOMNodeList|static $selector
104
     *
105
     * @return static
106 2
     */
107
    public function appendTo($selector)
108 2
    {
109
        $target = $this->targetResolve($selector);
110 2
111
        return $target->append($this);
112
    }
113
114
    /**
115
     * Insert content or node(s) to the beginning of each matched node.
116
     *
117
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
118
     *
119
     * @return static
120 3
     */
121
    public function prepend($content)
122 3
    {
123
        $content = $this->contentResolve($content);
124
125
        return $this->each(function (HtmlNode $node, $index) use ($content) {
126 3
            $content->each(function (DOMNode $newNode) use ($node, $index) {
127 3
                $newNode = $this->newNode($newNode, $index);
128 3
                $node->prepend($newNode);
129 3
            }, true);
130
        });
131
    }
132
133
    /**
134
     * Insert every matched node to the beginning of the target.
135
     *
136
     * @param string|DOMNode|DOMNode[]DOMNodeList|static $selector
137
     *
138
     * @return static
139 2
     */
140
    public function prependTo($selector)
141 2
    {
142
        $target = $this->targetResolve($selector);
143 2
144
        return $target->prepend($this);
145
    }
146
147
    /**
148
     * Replace each matched node with the provided new content or node(s)
149
     *
150
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
151
     *
152
     * @return static
153 2
     */
154
    public function replaceWith($content)
155 2
    {
156
        $content = $this->contentResolve($content);
157 2
        return $this->each(function (DOMNode $node, $index) use ($content) {
158 1
            if (!$node->parentNode) {
159
                return;
160
            }
161 2
162 2
            $len = $content->count();
163
            $content->each(
164 2
                function (DOMNode $newNode) use ($node, $index, $len) {
165
                    $newNode = $this->newNode($newNode, $index);
166 2
167 2
                    if ($len === 1) {
168
                        $node->parentNode->replaceChild($newNode, $node);
0 ignored issues
show
Bug introduced by
The method replaceChild() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

168
                        $node->parentNode->/** @scrutinizer ignore-call */ 
169
                                           replaceChild($newNode, $node);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
169 2
                    } else {
170
                        $this->resolve($newNode)->insertAfter($node);
171 2
                    }
172 2
                },
173
                true
174
            );
175 2
176 2
            if ($len !== 1) {
177
                $node->parentNode->removeChild($node);
178 2
            }
179
        });
180
    }
181
182
    /**
183
     * Replace each target node with the matched node(s)
184
     *
185
     * @param string|DOMNode|DOMNode[]DOMNodeList|static $selector
186
     *
187
     * @return static
188 1
     */
189
    public function replaceAll($selector)
190 1
    {
191
        $target = $this->targetResolve($selector);
192 1
193
        return $target->replaceWith($this);
194
    }
195
196
    /**
197
     * Wrap an HTML structure around each matched node.
198
     *
199
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
200
     *
201
     * @return static
202 3
     */
203
    public function wrap($content)
204 3
    {
205 3
        $content = $this->contentResolve($content);
206
        $newNode = $content[0];
207 3
208 1
        if (empty($newNode)) {
209
            return $this;
210
        }
211
212 3
        return $this->each(function (DOMNode $node, $index) use ($newNode) {
213
            $newNode = $this->newNode($newNode, $index);
214 3
215 3
            $nodes = $this->xpathQuery('descendant::*[last()]', $newNode);
216 1
            if (!$nodes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $nodes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
217
                throw new Exception('Invalid wrap html format.');
218
            }
219 3
220 3
            $deepestNode = end($nodes);
221 3
            $node->parentNode->replaceChild($newNode, $node);
222 3
            $deepestNode->appendChild($node);
223
        });
224
    }
225
226
    /**
227
     * Wrap an HTML structure around the content of each matched node.
228
     *
229
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
230
     *
231
     * @return static
232 1
     */
233
    public function wrapInner($content)
234 1
    {
235 1
        $content = $this->contentResolve($content);
236
        $newNode = $content[0];
237 1
238 1
        if (empty($newNode)) {
239
            return $this;
240
        }
241
242 1
        return $this->each(function (DOMNode $node, $index) use ($newNode) {
243
            $newNode = $this->newNode($newNode, $index);
244 1
245 1
            $nodes = $this->xpathQuery('descendant::*[last()]', $newNode);
246 1
            if (!$nodes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $nodes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
247
                throw new Exception('Invalid wrap html format.');
248
            }
249 1
250
            $deepestNode = end($nodes);
251 1
252 1
            foreach (iterator_to_array($node->childNodes) as $childNode) {
253
                $deepestNode->appendChild($childNode);
254
            }
255 1
256 1
            $node->appendChild($newNode);
257
        });
258
    }
259
260
    /**
261
     * Wrap an HTML structure around all matched nodes.
262
     *
263
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
264
     *
265
     * @return static
266 1
     */
267
    public function wrapAll($content)
268 1
    {
269 1
        $content = $this->contentResolve($content);
270 1
        if (!$content->count()) {
271
            return $this;
272
        }
273 1
274
        $newNode = $content[0];
275 1
        $this->each(function (DOMNode $node, $index) use ($newNode) {
276 1
            if ($index === 0) {
277
                $this->resolve($node)->wrap($newNode);
278 1
            } else {
279
                $this->nodes[0]->parentNode->appendChild($node);
0 ignored issues
show
Bug introduced by
The method appendChild() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

279
                $this->nodes[0]->parentNode->/** @scrutinizer ignore-call */ 
280
                                             appendChild($node);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
280 1
            }
281
        });
282 1
283
        return $this;
284
    }
285
286
    /**
287
     * Remove the parents of the matched nodes from the DOM.
288
     * A optional selector to check the parent node against.
289
     *
290
     * @param string|null $selector
291
     *
292
     * @return static
293 2
     */
294
    public function unwrap(?string $selector = null)
295 2
    {
296
        return $this->parent($selector)->unwrapSelf();
297
    }
298
299
    /**
300
     * Remove the HTML tag of the matched nodes from the DOM.
301
     * Leaving the child nodes in their place.
302
     *
303
     * @return static
304 3
     */
305
    public function unwrapSelf()
306
    {
307 3
        return $this->each(function (HtmlNode $node) {
308 3
            $node->unwrapSelf();
309
        });
310
    }
311
312
    /**
313
     * When the selection needs a new node, return the original one or a clone.
314
     *
315
     * @param DOMNode $newNode
316
     * @param int     $index
317
     *
318
     * @return DOMNode
319 17
     */
320
    protected function newNode(DOMNode $newNode, int $index)
321 17
    {
322 13
        return $index !== $this->count() - 1
323 17
            ? $newNode->cloneNode(true)
324
            : $newNode;
325
    }
326
}
327