Completed
Branch scrutinizer (607e7a)
by Thomas
02:04
created

HtmlQueryNode::newNode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 5
rs 10
1
<?php
2
3
namespace Sulao\HtmlQuery;
4
5
use DOMNode, DOMNodeList;
6
7
/**
8
 * Class HtmlQueryNode
9
 *
10
 * @package Sulao\HtmlQuery
11
 */
12
abstract class HtmlQueryNode extends HtmlQueryAttribute
13
{
14
    /**
15
     * Insert content or node(s) before each matched node.
16
     *
17
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
18
     *
19
     * @return static
20
     */
21
    public function before($content)
22
    {
23
        $content = $this->contentResolve($content);
24
25
        return $this->each(function (HtmlNode $node, $index) use ($content) {
26
            $content->each(function (DOMNode $newNode) use ($node, $index) {
27
                $newNode = $this->newNode($newNode, $index);
28
                $node->before($newNode);
29
            });
30
        });
31
    }
32
33
    /**
34
     * Insert every matched node before the target.
35
     *
36
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $selector
37
     *
38
     * @return static
39
     */
40
    public function insertBefore($selector)
41
    {
42
        $target = $this->targetResolve($selector);
43
44
        return $target->before($this);
45
    }
46
47
    /**
48
     * Insert content or node(s) after each matched node.
49
     *
50
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
51
     *
52
     * @return static
53
     */
54
    public function after($content)
55
    {
56
        $content = $this->contentResolve($content);
57
58
        return $this->each(function (HtmlNode $node, $index) use ($content) {
59
            $content->each(function (DOMNode $newNode) use ($node, $index) {
60
                $newNode = $this->newNode($newNode, $index);
61
                $node->after($newNode);
62
            }, true);
63
        });
64
    }
65
66
    /**
67
     * Insert every matched node after the target.
68
     *
69
     * @param string|DOMNode|DOMNode[]DOMNodeList|static $selector
70
     *
71
     * @return static
72
     */
73
    public function insertAfter($selector)
74
    {
75
        $target = $this->targetResolve($selector);
76
77
        return $target->after($this);
78
    }
79
80
    /**
81
     * Insert content or node(s) to the end of every matched node.
82
     *
83
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
84
     *
85
     * @return static
86
     */
87
    public function append($content)
88
    {
89
        $content = $this->contentResolve($content);
90
91
        return $this->each(function (HtmlNode $node, $index) use ($content) {
92
            $content->each(function (DOMNode $newNode) use ($node, $index) {
93
                $newNode = $this->newNode($newNode, $index);
94
                $node->append($newNode);
95
            });
96
        });
97
    }
98
99
    /**
100
     * Insert every matched node to the end of the target.
101
     *
102
     * @param string|DOMNode|DOMNode[]DOMNodeList|static $selector
103
     *
104
     * @return static
105
     */
106
    public function appendTo($selector)
107
    {
108
        $target = $this->targetResolve($selector);
109
110
        return $target->append($this);
111
    }
112
113
    /**
114
     * Insert content or node(s) to the beginning of each matched node.
115
     *
116
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
117
     *
118
     * @return static
119
     */
120
    public function prepend($content)
121
    {
122
        $content = $this->contentResolve($content);
123
124
        return $this->each(function (HtmlNode $node, $index) use ($content) {
125
            $content->each(function (DOMNode $newNode) use ($node, $index) {
126
                $newNode = $this->newNode($newNode, $index);
127
                $node->prepend($newNode);
128
            }, true);
129
        });
130
    }
131
132
    /**
133
     * Insert every matched node to the beginning of the target.
134
     *
135
     * @param string|DOMNode|DOMNode[]DOMNodeList|static $selector
136
     *
137
     * @return static
138
     */
139
    public function prependTo($selector)
140
    {
141
        $target = $this->targetResolve($selector);
142
143
        return $target->prepend($this);
144
    }
145
146
    /**
147
     * Replace each matched node with the provided new content or node(s)
148
     *
149
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
150
     *
151
     * @return static
152
     */
153
    public function replaceWith($content)
154
    {
155
        $content = $this->contentResolve($content);
156
        return $this->each(function (DOMNode $node, $index) use ($content) {
157
            if (!$node->parentNode) {
158
                return;
159
            }
160
161
            $len = $content->count();
162
            $content->each(
163
                function (DOMNode $newNode) use ($node, $index, $len) {
164
                    $newNode = $this->newNode($newNode, $index);
165
166
                    if ($len === 1) {
167
                        $node->parentNode->replaceChild($newNode, $node);
168
                    } else {
169
                        $this->resolve($newNode)->insertAfter($node);
170
                    }
171
                },
172
                true
173
            );
174
175
            if ($len !== 1) {
176
                $node->parentNode->removeChild($node);
177
            }
178
        });
179
    }
180
181
    /**
182
     * Replace each target node with the matched node(s)
183
     *
184
     * @param string|DOMNode|DOMNode[]DOMNodeList|static $selector
185
     *
186
     * @return static
187
     */
188
    public function replaceAll($selector)
189
    {
190
        $target = $this->targetResolve($selector);
191
192
        return $target->replaceWith($this);
193
    }
194
195
    /**
196
     * Wrap an HTML structure around each matched node.
197
     *
198
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
199
     *
200
     * @return static
201
     */
202
    public function wrap($content)
203
    {
204
        $content = $this->contentResolve($content);
205
        $newNode = $content[0];
206
207
        if (empty($newNode)) {
208
            return $this;
209
        }
210
211
        return $this->each(function (DOMNode $node, $index) use ($newNode) {
212
            $newNode = $this->newNode($newNode, $index);
213
214
            $nodes = $this->xpathQuery('descendant::*[last()]', $newNode);
215
            if (!$nodes) {
216
                throw new Exception('Invalid wrap html format.');
217
            }
218
219
            $deepestNode = end($nodes);
220
            $node->parentNode->replaceChild($newNode, $node);
221
            $deepestNode->appendChild($node);
222
        });
223
    }
224
225
    /**
226
     * Wrap an HTML structure around the content of each matched node.
227
     *
228
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
229
     *
230
     * @return static
231
     */
232
    public function wrapInner($content)
233
    {
234
        $content = $this->contentResolve($content);
235
        $newNode = $content[0];
236
237
        if (empty($newNode)) {
238
            return $this;
239
        }
240
241
        return $this->each(function (DOMNode $node, $index) use ($newNode) {
242
            $newNode = $this->newNode($newNode, $index);
243
244
            $nodes = $this->xpathQuery('descendant::*[last()]', $newNode);
245
            if (!$nodes) {
246
                throw new Exception('Invalid wrap html format.');
247
            }
248
249
            $deepestNode = end($nodes);
250
251
            foreach (iterator_to_array($node->childNodes) as $childNode) {
252
                $deepestNode->appendChild($childNode);
253
            }
254
255
            $node->appendChild($newNode);
256
        });
257
    }
258
259
    /**
260
     * Wrap an HTML structure around all matched nodes.
261
     *
262
     * @param string|DOMNode|DOMNode[]|DOMNodeList|static $content
263
     *
264
     * @return static
265
     */
266
    public function wrapAll($content)
267
    {
268
        $content = $this->contentResolve($content);
269
        if (!$content->count()) {
270
            return $this;
271
        }
272
273
        $newNode = $content[0];
274
        $this->each(function (DOMNode $node, $index) use ($newNode) {
275
            if ($index === 0) {
276
                $this->resolve($node)->wrap($newNode);
277
            } else {
278
                $this->nodes[0]->parentNode->appendChild($node);
279
            }
280
        });
281
282
        return $this;
283
    }
284
285
    /**
286
     * Remove the parents of the matched nodes from the DOM.
287
     * A optional selector to check the parent node against.
288
     *
289
     * @param string|null $selector
290
     *
291
     * @return static
292
     */
293
    public function unwrap(?string $selector = null)
294
    {
295
        return $this->parent($selector)->unwrapSelf();
296
    }
297
298
    /**
299
     * Remove the HTML tag of the matched nodes from the DOM.
300
     * Leaving the child nodes in their place.
301
     *
302
     * @return static
303
     */
304
    public function unwrapSelf()
305
    {
306
        return $this->each(function (HtmlNode $node) {
307
            $node->unwrapSelf();
308
        });
309
    }
310
311
    /**
312
     * When the selection needs a new node, return the original one or a clone.
313
     *
314
     * @param DOMNode $newNode
315
     * @param int     $index
316
     *
317
     * @return DOMNode
318
     */
319
    protected function newNode(DOMNode $newNode, int $index)
320
    {
321
        return $index !== $this->count() - 1
322
            ? $newNode->cloneNode(true)
323
            : $newNode;
324
    }
325
}
326