Issues (9)

src/HtmlQueryNode.php (4 issues)

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
     */
22 3
    public function before($content)
23
    {
24 3
        $content = $this->contentResolve($content);
25
26 3
        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 3
        });
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
     */
41 1
    public function insertBefore($selector)
42
    {
43 1
        $target = $this->targetResolve($selector);
44
45 1
        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
     */
55 5
    public function after($content)
56
    {
57 5
        $content = $this->contentResolve($content);
58
59 5
        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 5
        });
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
     */
74 3
    public function insertAfter($selector)
75
    {
76 3
        $target = $this->targetResolve($selector);
77
78 3
        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
     */
88 6
    public function append($content)
89
    {
90 6
        $content = $this->contentResolve($content);
91
92 6
        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 6
        });
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
     */
107 2
    public function appendTo($selector)
108
    {
109 2
        $target = $this->targetResolve($selector);
110
111 2
        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
     */
121 3
    public function prepend($content)
122
    {
123 3
        $content = $this->contentResolve($content);
124
125 3
        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 3
        });
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
     */
140 2
    public function prependTo($selector)
141
    {
142 2
        $target = $this->targetResolve($selector);
143
144 2
        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
     */
154 2
    public function replaceWith($content)
155
    {
156 2
        $content = $this->contentResolve($content);
157 2
        return $this->each(function (DOMNode $node, $index) use ($content) {
158 2
            if (!$node->parentNode) {
159 1
                return;
160
            }
161
162 2
            $len = $content->count();
163 2
            $content->each(
164 2
                function (DOMNode $newNode) use ($node, $index, $len) {
165 2
                    $newNode = $this->newNode($newNode, $index);
166
167 2
                    if ($len === 1) {
168 2
                        $node->parentNode->replaceChild($newNode, $node);
0 ignored issues
show
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
                    } else {
170 2
                        $this->resolve($newNode)->insertAfter($node);
171
                    }
172 2
                },
173 2
                true
174 2
            );
175
176 2
            if ($len !== 1) {
177 2
                $node->parentNode->removeChild($node);
178
            }
179 2
        });
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
     */
189 1
    public function replaceAll($selector)
190
    {
191 1
        $target = $this->targetResolve($selector);
192
193 1
        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
     */
203 3
    public function wrap($content)
204
    {
205 3
        $content = $this->contentResolve($content);
206 3
        $newNode = $content[0];
207
208 3
        if (empty($newNode)) {
209 1
            return $this;
210
        }
211
212 3
        return $this->each(function (DOMNode $node, $index) use ($newNode) {
213 3
            $newNode = $this->newNode($newNode, $index);
214
215 3
            $nodes = $this->xpathQuery('descendant::*[last()]', $newNode);
216 3
            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 1
                throw new Exception('Invalid wrap html format.');
218
            }
219
220 3
            $deepestNode = end($nodes);
221 3
            $node->parentNode->replaceChild($newNode, $node);
222 3
            $deepestNode->appendChild($node);
223 3
        });
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
     */
233 1
    public function wrapInner($content)
234
    {
235 1
        $content = $this->contentResolve($content);
236 1
        $newNode = $content[0];
237
238 1
        if (empty($newNode)) {
239 1
            return $this;
240
        }
241
242 1
        return $this->each(function (DOMNode $node, $index) use ($newNode) {
243 1
            $newNode = $this->newNode($newNode, $index);
244
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 1
                throw new Exception('Invalid wrap html format.');
248
            }
249
250 1
            $deepestNode = end($nodes);
251
252 1
            foreach (iterator_to_array($node->childNodes) as $childNode) {
253 1
                $deepestNode->appendChild($childNode);
254
            }
255
256 1
            $node->appendChild($newNode);
257 1
        });
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
     */
267 1
    public function wrapAll($content)
268
    {
269 1
        $content = $this->contentResolve($content);
270 1
        if (!$content->count()) {
271 1
            return $this;
272
        }
273
274 1
        $newNode = $content[0];
275 1
        $this->each(function (DOMNode $node, $index) use ($newNode) {
276 1
            if ($index === 0) {
277 1
                $this->resolve($node)->wrap($newNode);
278
            } else {
279 1
                $this->nodes[0]->parentNode->appendChild($node);
0 ignored issues
show
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
            }
281 1
        });
282
283 1
        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
     */
294 2
    public function unwrap(?string $selector = null)
295
    {
296 2
        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
     */
305 3
    public function unwrapSelf()
306
    {
307 3
        return $this->each(function (HtmlNode $node) {
308 3
            $node->unwrapSelf();
309 3
        });
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
     */
320 17
    protected function newNode(DOMNode $newNode, int $index)
321
    {
322 17
        return $index !== $this->count() - 1
323 13
            ? $newNode->cloneNode(true)
324 17
            : $newNode;
325
    }
326
}
327