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
|
|||||||
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
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 ![]() |
|||||||
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
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 ![]() |
|||||||
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
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. ![]() |
|||||||
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 |
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.