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
|
|||||||
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
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 | 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
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 | 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
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 | 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 |
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.