This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Wa72\HtmlPageDom; |
||
3 | |||
4 | use Symfony\Component\DomCrawler\Crawler; |
||
5 | |||
6 | /** |
||
7 | * Extends \Symfony\Component\DomCrawler\Crawler by adding tree manipulation functions |
||
8 | * for HTML documents inspired by jQuery such as setInnerHtml(), css(), append(), prepend(), before(), |
||
9 | * addClass(), removeClass() |
||
10 | * |
||
11 | * @author Christoph Singer |
||
12 | * @license MIT |
||
13 | * |
||
14 | */ |
||
15 | class HtmlPageCrawler extends Crawler |
||
16 | { |
||
17 | /** |
||
18 | * the (internal) root element name used when importing html fragments |
||
19 | * */ |
||
20 | const FRAGMENT_ROOT_TAGNAME = '_root'; |
||
21 | |||
22 | /** |
||
23 | * Get an HtmlPageCrawler object from a HTML string, DOMNode, DOMNodeList or HtmlPageCrawler |
||
24 | * |
||
25 | * This is the equivalent to jQuery's $() function when used for wrapping DOMNodes or creating DOMElements from HTML code. |
||
26 | * |
||
27 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList|array $content |
||
28 | * @return HtmlPageCrawler |
||
29 | * @api |
||
30 | */ |
||
31 | 17 | public static function create($content) |
|
32 | { |
||
33 | 17 | if ($content instanceof HtmlPageCrawler) { |
|
34 | 3 | return $content; |
|
35 | } else { |
||
36 | 17 | return new HtmlPageCrawler($content); |
|
37 | } |
||
38 | } |
||
39 | |||
40 | /** |
||
41 | * Adds the specified class(es) to each element in the set of matched elements. |
||
42 | * |
||
43 | * @param string $name One or more space-separated classes to be added to the class attribute of each matched element. |
||
44 | * @return HtmlPageCrawler $this for chaining |
||
45 | * @api |
||
46 | */ |
||
47 | 1 | public function addClass($name) |
|
48 | { |
||
49 | 1 | foreach ($this as $node) { |
|
50 | 1 | if ($node instanceof \DOMElement) { |
|
51 | /** @var \DOMElement $node */ |
||
52 | 1 | $classes = preg_split('/\s+/s', $node->getAttribute('class')); |
|
53 | 1 | $found = false; |
|
54 | 1 | $count = count($classes); |
|
55 | 1 | for ($i = 0; $i < $count; $i++) { |
|
56 | 1 | if ($classes[$i] == $name) { |
|
57 | 1 | $found = true; |
|
58 | } |
||
59 | } |
||
60 | 1 | if (!$found) { |
|
61 | 1 | $classes[] = $name; |
|
62 | 1 | $node->setAttribute('class', trim(join(' ', $classes))); |
|
63 | } |
||
64 | } |
||
65 | } |
||
66 | 1 | return $this; |
|
67 | } |
||
68 | |||
69 | /** |
||
70 | * Insert content, specified by the parameter, after each element in the set of matched elements. |
||
71 | * |
||
72 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $content |
||
73 | * @return HtmlPageCrawler $this for chaining |
||
74 | * @api |
||
75 | */ |
||
76 | 3 | public function after($content) |
|
77 | { |
||
78 | 3 | $content = self::create($content); |
|
79 | 3 | $newnodes = array(); |
|
80 | 3 | foreach ($this as $i => $node) { |
|
81 | /** @var \DOMNode $node */ |
||
82 | 3 | $refnode = $node->nextSibling; |
|
83 | 3 | foreach ($content as $newnode) { |
|
84 | /** @var \DOMNode $newnode */ |
||
85 | 3 | $newnode = static::importNewnode($newnode, $node, $i); |
|
86 | 3 | if ($refnode === null) { |
|
87 | 3 | $node->parentNode->appendChild($newnode); |
|
88 | } else { |
||
89 | 1 | $node->parentNode->insertBefore($newnode, $refnode); |
|
90 | } |
||
91 | 3 | $newnodes[] = $newnode; |
|
92 | } |
||
93 | } |
||
94 | 3 | $content->clear(); |
|
95 | 3 | $content->add($newnodes); |
|
96 | 3 | return $this; |
|
97 | } |
||
98 | |||
99 | /** |
||
100 | * Insert HTML content as child nodes of each element after existing children |
||
101 | * |
||
102 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $content HTML code fragment or DOMNode to append |
||
103 | * @return HtmlPageCrawler $this for chaining |
||
104 | * @api |
||
105 | */ |
||
106 | 2 | public function append($content) |
|
107 | { |
||
108 | 2 | $content = self::create($content); |
|
109 | 2 | $newnodes = array(); |
|
110 | 2 | foreach ($this as $i => $node) { |
|
111 | /** @var \DOMNode $node */ |
||
112 | 2 | foreach ($content as $newnode) { |
|
113 | /** @var \DOMNode $newnode */ |
||
114 | 2 | $newnode = static::importNewnode($newnode, $node, $i); |
|
115 | 2 | $node->appendChild($newnode); |
|
116 | 2 | $newnodes[] = $newnode; |
|
117 | } |
||
118 | } |
||
119 | 2 | $content->clear(); |
|
120 | 2 | $content->add($newnodes); |
|
121 | 2 | return $this; |
|
122 | } |
||
123 | |||
124 | /** |
||
125 | * Insert every element in the set of matched elements to the end of the target. |
||
126 | * |
||
127 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $element |
||
128 | * @return \Wa72\HtmlPageDom\HtmlPageCrawler A new Crawler object containing all elements appended to the target elements |
||
129 | * @api |
||
130 | */ |
||
131 | 2 | public function appendTo($element) |
|
132 | { |
||
133 | 2 | $e = self::create($element); |
|
134 | 2 | $newnodes = array(); |
|
135 | 2 | foreach ($e as $i => $node) { |
|
136 | /** @var \DOMNode $node */ |
||
137 | 2 | foreach ($this as $newnode) { |
|
138 | /** @var \DOMNode $newnode */ |
||
139 | 2 | if ($node !== $newnode) { |
|
140 | 2 | $newnode = static::importNewnode($newnode, $node, $i); |
|
141 | 2 | $node->appendChild($newnode); |
|
142 | } |
||
143 | 2 | $newnodes[] = $newnode; |
|
144 | } |
||
145 | } |
||
146 | 2 | return self::create($newnodes); |
|
147 | } |
||
148 | |||
149 | /** |
||
150 | * Sets an attribute on each element |
||
151 | * |
||
152 | * @param string $name |
||
153 | * @param string $value |
||
154 | * @return HtmlPageCrawler $this for chaining |
||
155 | * @api |
||
156 | */ |
||
157 | 3 | public function setAttribute($name, $value) |
|
158 | { |
||
159 | 3 | foreach ($this as $node) { |
|
160 | 3 | if ($node instanceof \DOMElement) { |
|
161 | /** @var \DOMElement $node */ |
||
162 | 3 | $node->setAttribute($name, $value); |
|
163 | } |
||
164 | } |
||
165 | 3 | return $this; |
|
166 | } |
||
167 | |||
168 | /** |
||
169 | * Returns the attribute value of the first node of the list. |
||
170 | * This is just an alias for attr() for naming consistency with setAttribute() |
||
171 | * |
||
172 | * @param string $name The attribute name |
||
173 | * @return string|null The attribute value or null if the attribute does not exist |
||
174 | * @throws \InvalidArgumentException When current node is empty |
||
175 | */ |
||
176 | 1 | public function getAttribute($name) |
|
177 | { |
||
178 | 1 | return parent::attr($name); |
|
0 ignored issues
–
show
|
|||
179 | } |
||
180 | |||
181 | /** |
||
182 | * Insert content, specified by the parameter, before each element in the set of matched elements. |
||
183 | * |
||
184 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $content |
||
185 | * @return HtmlPageCrawler $this for chaining |
||
186 | * @api |
||
187 | */ |
||
188 | 2 | public function before($content) |
|
189 | { |
||
190 | 2 | $content = self::create($content); |
|
191 | 2 | $newnodes = array(); |
|
192 | 2 | foreach ($this as $i => $node) { |
|
193 | /** @var \DOMNode $node */ |
||
194 | 2 | foreach ($content as $newnode) { |
|
195 | /** @var \DOMNode $newnode */ |
||
196 | 2 | if ($node !== $newnode) { |
|
197 | 2 | $newnode = static::importNewnode($newnode, $node, $i); |
|
198 | 2 | $node->parentNode->insertBefore($newnode, $node); |
|
199 | 2 | $newnodes[] = $newnode; |
|
200 | } |
||
201 | } |
||
202 | } |
||
203 | 2 | $content->clear(); |
|
204 | 2 | $content->add($newnodes); |
|
205 | 2 | return $this; |
|
206 | } |
||
207 | |||
208 | /** |
||
209 | * Create a deep copy of the set of matched elements. |
||
210 | * |
||
211 | * Equivalent to clone() in jQuery (clone is not a valid PHP function name) |
||
212 | * |
||
213 | * @return HtmlPageCrawler |
||
214 | * @api |
||
215 | */ |
||
216 | 1 | public function makeClone() |
|
217 | { |
||
218 | 1 | return clone $this; |
|
219 | } |
||
220 | |||
221 | 1 | public function __clone() |
|
222 | { |
||
223 | 1 | $newnodes = array(); |
|
224 | 1 | foreach ($this as $node) { |
|
225 | /** @var \DOMNode $node */ |
||
226 | 1 | $newnodes[] = $node->cloneNode(true); |
|
227 | } |
||
228 | 1 | $this->clear(); |
|
229 | 1 | $this->add($newnodes); |
|
230 | 1 | } |
|
231 | |||
232 | /** |
||
233 | * Get one CSS style property of the first element or set it for all elements in the list |
||
234 | * |
||
235 | * Function is here for compatibility with jQuery; it is the same as getStyle() and setStyle() |
||
236 | * |
||
237 | * @see HtmlPageCrawler::getStyle() |
||
238 | * @see HtmlPageCrawler::setStyle() |
||
239 | * |
||
240 | * @param string $key The name of the style property |
||
241 | * @param null|string $value The CSS value to set, or NULL to get the current value |
||
242 | * @return HtmlPageCrawler|string If no param is provided, returns the CSS styles of the first element |
||
243 | * @api |
||
244 | */ |
||
245 | 1 | public function css($key, $value = null) |
|
246 | { |
||
247 | 1 | if (null === $value) { |
|
248 | 1 | return $this->getStyle($key); |
|
249 | } else { |
||
250 | 1 | return $this->setStyle($key, $value); |
|
251 | } |
||
252 | } |
||
253 | |||
254 | /** |
||
255 | * get one CSS style property of the first element |
||
256 | * |
||
257 | * @param string $key name of the property |
||
258 | * @return string|null value of the property |
||
259 | */ |
||
260 | 1 | public function getStyle($key) |
|
261 | { |
||
262 | 1 | $styles = Helpers::cssStringToArray($this->getAttribute('style')); |
|
263 | 1 | return (isset($styles[$key]) ? $styles[$key] : null); |
|
264 | } |
||
265 | |||
266 | /** |
||
267 | * set one CSS style property for all elements in the list |
||
268 | * |
||
269 | * @param string $key name of the property |
||
270 | * @param string $value value of the property |
||
271 | * @return HtmlPageCrawler $this for chaining |
||
272 | */ |
||
273 | 1 | public function setStyle($key, $value) |
|
274 | { |
||
275 | 1 | foreach ($this as $node) { |
|
276 | 1 | if ($node instanceof \DOMElement) { |
|
277 | /** @var \DOMElement $node */ |
||
278 | 1 | $styles = Helpers::cssStringToArray($node->getAttribute('style')); |
|
279 | 1 | if ($value != '') { |
|
280 | 1 | $styles[$key] = $value; |
|
281 | 1 | } elseif (isset($styles[$key])) { |
|
282 | 1 | unset($styles[$key]); |
|
283 | } |
||
284 | 1 | $node->setAttribute('style', Helpers::cssArrayToString($styles)); |
|
285 | } |
||
286 | } |
||
287 | 1 | return $this; |
|
288 | } |
||
289 | |||
290 | /** |
||
291 | * Removes all child nodes and text from all nodes in set |
||
292 | * |
||
293 | * Equivalent to jQuery's empty() function which is not a valid function name in PHP |
||
294 | * @return HtmlPageCrawler $this |
||
295 | * @api |
||
296 | */ |
||
297 | 1 | public function makeEmpty() |
|
298 | { |
||
299 | 1 | foreach ($this as $node) { |
|
300 | 1 | $node->nodeValue = ''; |
|
301 | } |
||
302 | 1 | return $this; |
|
303 | } |
||
304 | |||
305 | /** |
||
306 | * Determine whether any of the matched elements are assigned the given class. |
||
307 | * |
||
308 | * @param string $name |
||
309 | * @return bool |
||
310 | * @api |
||
311 | */ |
||
312 | 2 | public function hasClass($name) |
|
313 | { |
||
314 | 2 | foreach ($this as $node) { |
|
315 | 2 | if ($node instanceof \DOMElement && $class = $node->getAttribute('class')) { |
|
316 | 2 | $classes = preg_split('/\s+/s', $class); |
|
317 | 2 | if (in_array($name, $classes)) { |
|
318 | 2 | return true; |
|
319 | } |
||
320 | } |
||
321 | } |
||
322 | 2 | return false; |
|
323 | } |
||
324 | |||
325 | /** |
||
326 | * Set the HTML contents of each element |
||
327 | * |
||
328 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $content HTML code fragment |
||
329 | * @return HtmlPageCrawler $this for chaining |
||
330 | * @api |
||
331 | */ |
||
332 | 3 | public function setInnerHtml($content) |
|
333 | { |
||
334 | 3 | $content = self::create($content); |
|
335 | 3 | foreach ($this as $node) { |
|
336 | 3 | $node->nodeValue = ''; |
|
337 | 3 | foreach ($content as $newnode) { |
|
338 | /** @var \DOMNode $node */ |
||
339 | /** @var \DOMNode $newnode */ |
||
340 | 3 | $newnode = static::importNewnode($newnode, $node); |
|
341 | 3 | $node->appendChild($newnode); |
|
342 | } |
||
343 | } |
||
344 | 3 | return $this; |
|
345 | } |
||
346 | |||
347 | /** |
||
348 | * Alias for Crawler::html() for naming consistency with setInnerHtml() |
||
349 | * |
||
350 | * @return string |
||
351 | * @api |
||
352 | */ |
||
353 | 1 | public function getInnerHtml() |
|
354 | { |
||
355 | 1 | return parent::html(); |
|
0 ignored issues
–
show
It seems like you call parent on a different method (
html() instead of getInnerHtml() ). Are you sure this is correct? If so, you might want to change this to $this->html() .
This check looks for a call to a parent method whose name is different than the method from which it is called. Consider the following code: class Daddy
{
protected function getFirstName()
{
return "Eidur";
}
protected function getSurName()
{
return "Gudjohnsen";
}
}
class Son
{
public function getFirstName()
{
return parent::getSurname();
}
}
The ![]() |
|||
356 | } |
||
357 | |||
358 | /** |
||
359 | * Insert every element in the set of matched elements after the target. |
||
360 | * |
||
361 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $element |
||
362 | * @return \Wa72\HtmlPageDom\HtmlPageCrawler A new Crawler object containing all elements appended to the target elements |
||
363 | * @api |
||
364 | */ |
||
365 | 2 | public function insertAfter($element) |
|
366 | { |
||
367 | 2 | $e = self::create($element); |
|
368 | 2 | $newnodes = array(); |
|
369 | 2 | foreach ($e as $i => $node) { |
|
370 | /** @var \DOMNode $node */ |
||
371 | 2 | $refnode = $node->nextSibling; |
|
372 | 2 | foreach ($this as $newnode) { |
|
373 | /** @var \DOMNode $newnode */ |
||
374 | 2 | $newnode = static::importNewnode($newnode, $node, $i); |
|
375 | 2 | if ($refnode === null) { |
|
376 | 2 | $node->parentNode->appendChild($newnode); |
|
377 | } else { |
||
378 | 1 | $node->parentNode->insertBefore($newnode, $refnode); |
|
379 | } |
||
380 | 2 | $newnodes[] = $newnode; |
|
381 | } |
||
382 | } |
||
383 | 2 | return self::create($newnodes); |
|
384 | } |
||
385 | |||
386 | /** |
||
387 | * Insert every element in the set of matched elements before the target. |
||
388 | * |
||
389 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $element |
||
390 | * @return \Wa72\HtmlPageDom\HtmlPageCrawler A new Crawler object containing all elements appended to the target elements |
||
391 | * @api |
||
392 | */ |
||
393 | 2 | public function insertBefore($element) |
|
394 | { |
||
395 | 2 | $e = self::create($element); |
|
396 | 2 | $newnodes = array(); |
|
397 | 2 | foreach ($e as $i => $node) { |
|
398 | /** @var \DOMNode $node */ |
||
399 | 2 | foreach ($this as $newnode) { |
|
400 | /** @var \DOMNode $newnode */ |
||
401 | 2 | $newnode = static::importNewnode($newnode, $node, $i); |
|
402 | 2 | if ($newnode !== $node) { |
|
403 | 2 | $node->parentNode->insertBefore($newnode, $node); |
|
404 | } |
||
405 | 2 | $newnodes[] = $newnode; |
|
406 | } |
||
407 | } |
||
408 | 2 | return self::create($newnodes); |
|
409 | } |
||
410 | |||
411 | /** |
||
412 | * Insert content, specified by the parameter, to the beginning of each element in the set of matched elements. |
||
413 | * |
||
414 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $content HTML code fragment |
||
415 | * @return HtmlPageCrawler $this for chaining |
||
416 | * @api |
||
417 | */ |
||
418 | 2 | public function prepend($content) |
|
419 | { |
||
420 | 2 | $content = self::create($content); |
|
421 | 2 | $newnodes = array(); |
|
422 | 2 | foreach ($this as $i => $node) { |
|
423 | 2 | $refnode = $node->firstChild; |
|
424 | /** @var \DOMNode $node */ |
||
425 | 2 | foreach ($content as $newnode) { |
|
426 | /** @var \DOMNode $newnode */ |
||
427 | 2 | $newnode = static::importNewnode($newnode, $node, $i); |
|
428 | 2 | if ($refnode === null) { |
|
429 | 1 | $node->appendChild($newnode); |
|
430 | 2 | } else if ($refnode !== $newnode) { |
|
431 | 2 | $node->insertBefore($newnode, $refnode); |
|
432 | } |
||
433 | 2 | $newnodes[] = $newnode; |
|
434 | } |
||
435 | } |
||
436 | 2 | $content->clear(); |
|
437 | 2 | $content->add($newnodes); |
|
438 | 2 | return $this; |
|
439 | } |
||
440 | |||
441 | /** |
||
442 | * Insert every element in the set of matched elements to the beginning of the target. |
||
443 | * |
||
444 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $element |
||
445 | * @return \Wa72\HtmlPageDom\HtmlPageCrawler A new Crawler object containing all elements prepended to the target elements |
||
446 | * @api |
||
447 | */ |
||
448 | 1 | public function prependTo($element) |
|
449 | { |
||
450 | 1 | $e = self::create($element); |
|
451 | 1 | $newnodes = array(); |
|
452 | 1 | foreach ($e as $i => $node) { |
|
453 | 1 | $refnode = $node->firstChild; |
|
454 | /** @var \DOMNode $node */ |
||
455 | 1 | foreach ($this as $newnode) { |
|
456 | /** @var \DOMNode $newnode */ |
||
457 | 1 | $newnode = static::importNewnode($newnode, $node, $i); |
|
458 | 1 | if ($newnode !== $node) { |
|
459 | 1 | if ($refnode === null) { |
|
460 | 1 | $node->appendChild($newnode); |
|
461 | } else { |
||
462 | 1 | $node->insertBefore($newnode, $refnode); |
|
463 | } |
||
464 | } |
||
465 | 1 | $newnodes[] = $newnode; |
|
466 | } |
||
467 | } |
||
468 | 1 | return self::create($newnodes); |
|
469 | } |
||
470 | |||
471 | /** |
||
472 | * Remove the set of matched elements from the DOM. |
||
473 | * |
||
474 | * (as opposed to Crawler::clear() which detaches the nodes only from Crawler |
||
475 | * but leaves them in the DOM) |
||
476 | * |
||
477 | * @api |
||
478 | */ |
||
479 | 2 | public function remove() |
|
480 | { |
||
481 | 2 | foreach ($this as $node) { |
|
482 | /** |
||
483 | * @var \DOMNode $node |
||
484 | */ |
||
485 | 2 | if ($node->parentNode instanceof \DOMElement) { |
|
486 | 2 | $node->parentNode->removeChild($node); |
|
487 | } |
||
488 | } |
||
489 | 2 | $this->clear(); |
|
490 | 2 | } |
|
491 | |||
492 | /** |
||
493 | * Remove an attribute from each element in the set of matched elements. |
||
494 | * |
||
495 | * Alias for removeAttribute for compatibility with jQuery |
||
496 | * |
||
497 | * @param string $name |
||
498 | * @return HtmlPageCrawler |
||
499 | * @api |
||
500 | */ |
||
501 | 1 | public function removeAttr($name) |
|
502 | { |
||
503 | 1 | return $this->removeAttribute($name); |
|
504 | } |
||
505 | |||
506 | /** |
||
507 | * Remove an attribute from each element in the set of matched elements. |
||
508 | * |
||
509 | * @param string $name |
||
510 | * @return HtmlPageCrawler |
||
511 | */ |
||
512 | 1 | public function removeAttribute($name) |
|
513 | { |
||
514 | 1 | foreach ($this as $node) { |
|
515 | 1 | if ($node instanceof \DOMElement) { |
|
516 | /** @var \DOMElement $node */ |
||
517 | 1 | if ($node->hasAttribute($name)) { |
|
518 | 1 | $node->removeAttribute($name); |
|
519 | } |
||
520 | } |
||
521 | } |
||
522 | 1 | return $this; |
|
523 | } |
||
524 | |||
525 | /** |
||
526 | * Remove a class from each element in the list |
||
527 | * |
||
528 | * @param string $name |
||
529 | * @return HtmlPageCrawler $this for chaining |
||
530 | * @api |
||
531 | */ |
||
532 | 2 | public function removeClass($name) |
|
533 | { |
||
534 | 2 | foreach ($this as $node) { |
|
535 | 2 | if ($node instanceof \DOMElement) { |
|
536 | /** @var \DOMElement $node */ |
||
537 | 2 | $classes = preg_split('/\s+/s', $node->getAttribute('class')); |
|
538 | 2 | $count = count($classes); |
|
539 | 2 | for ($i = 0; $i < $count; $i++) { |
|
540 | 2 | if ($classes[$i] == $name) { |
|
541 | 2 | unset($classes[$i]); |
|
542 | } |
||
543 | } |
||
544 | 2 | $node->setAttribute('class', trim(join(' ', $classes))); |
|
545 | } |
||
546 | } |
||
547 | 2 | return $this; |
|
548 | } |
||
549 | |||
550 | /** |
||
551 | * Replace each target element with the set of matched elements. |
||
552 | * |
||
553 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $element |
||
554 | * @return \Wa72\HtmlPageDom\HtmlPageCrawler A new Crawler object containing all elements appended to the target elements |
||
555 | * @api |
||
556 | */ |
||
557 | 2 | public function replaceAll($element) |
|
558 | { |
||
559 | 2 | $e = self::create($element); |
|
560 | 2 | $newnodes = array(); |
|
561 | 2 | foreach ($e as $i => $node) { |
|
562 | /** @var \DOMNode $node */ |
||
563 | 2 | $parent = $node->parentNode; |
|
564 | 2 | $refnode = $node->nextSibling; |
|
565 | 2 | foreach ($this as $j => $newnode) { |
|
566 | /** @var \DOMNode $newnode */ |
||
567 | 2 | $newnode = static::importNewnode($newnode, $node, $i); |
|
568 | 2 | if ($j == 0) { |
|
569 | 2 | $parent->replaceChild($newnode, $node); |
|
570 | } else { |
||
571 | 1 | $parent->insertBefore($newnode, $refnode); |
|
572 | } |
||
573 | 2 | $newnodes[] = $newnode; |
|
574 | } |
||
575 | } |
||
576 | 2 | return self::create($newnodes); |
|
577 | } |
||
578 | |||
579 | /** |
||
580 | * Replace each element in the set of matched elements with the provided new content and return the set of elements that was removed. |
||
581 | * |
||
582 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $content |
||
583 | * @return \Wa72\HtmlPageDom\HtmlPageCrawler $this for chaining |
||
584 | * @api |
||
585 | */ |
||
586 | 2 | public function replaceWith($content) |
|
587 | { |
||
588 | 2 | $content = self::create($content); |
|
589 | 2 | $newnodes = array(); |
|
590 | 2 | foreach ($this as $i => $node) { |
|
591 | /** @var \DOMNode $node */ |
||
592 | 2 | $parent = $node->parentNode; |
|
593 | 2 | $refnode = $node->nextSibling; |
|
594 | 2 | foreach ($content as $j => $newnode) { |
|
595 | /** @var \DOMNode $newnode */ |
||
596 | 2 | $newnode = static::importNewnode($newnode, $node, $i); |
|
597 | 2 | if ($j == 0) { |
|
598 | 2 | $parent->replaceChild($newnode, $node); |
|
599 | } else { |
||
600 | 1 | $parent->insertBefore($newnode, $refnode); |
|
601 | } |
||
602 | 2 | $newnodes[] = $newnode; |
|
603 | } |
||
604 | } |
||
605 | 2 | $content->clear(); |
|
606 | 2 | $content->add($newnodes); |
|
607 | 2 | return $this; |
|
608 | } |
||
609 | |||
610 | /** |
||
611 | * Get the combined text contents of each element in the set of matched elements, including their descendants. |
||
612 | * This is what the jQuery text() function does, contrary to the Crawler::text() method that returns only |
||
613 | * the text of the first node. |
||
614 | * |
||
615 | * @return string |
||
616 | * @api |
||
617 | */ |
||
618 | 1 | public function getCombinedText() |
|
619 | { |
||
620 | 1 | $text = ''; |
|
621 | 1 | foreach ($this as $node) { |
|
622 | /** @var \DOMNode $node */ |
||
623 | 1 | $text .= $node->nodeValue; |
|
624 | } |
||
625 | 1 | return $text; |
|
626 | } |
||
627 | |||
628 | /** |
||
629 | * Set the text contents of the matched elements. |
||
630 | * |
||
631 | * @param string $text |
||
632 | * @return HtmlPageCrawler |
||
633 | * @api |
||
634 | */ |
||
635 | 2 | public function setText($text) |
|
636 | { |
||
637 | 2 | $text = htmlspecialchars($text); |
|
638 | 2 | foreach ($this as $node) { |
|
639 | /** @var \DOMNode $node */ |
||
640 | 2 | $node->nodeValue = $text; |
|
641 | } |
||
642 | 2 | return $this; |
|
643 | } |
||
644 | |||
645 | /** |
||
646 | * Add or remove one or more classes from each element in the set of matched elements, depending the class’s presence. |
||
647 | * |
||
648 | * @param string $classname One or more classnames separated by spaces |
||
649 | * @return \Wa72\HtmlPageDom\HtmlPageCrawler $this for chaining |
||
650 | * @api |
||
651 | */ |
||
652 | 1 | public function toggleClass($classname) |
|
653 | { |
||
654 | 1 | $classes = explode(' ', $classname); |
|
655 | 1 | foreach ($this as $i => $node) { |
|
656 | 1 | $c = self::create($node); |
|
657 | /** @var \DOMNode $node */ |
||
658 | 1 | foreach ($classes as $class) { |
|
659 | 1 | if ($c->hasClass($class)) { |
|
660 | 1 | $c->removeClass($class); |
|
661 | } else { |
||
662 | 1 | $c->addClass($class); |
|
663 | } |
||
664 | } |
||
665 | } |
||
666 | 1 | return $this; |
|
667 | } |
||
668 | |||
669 | /** |
||
670 | * Remove the parents of the set of matched elements from the DOM, leaving the matched elements in their place. |
||
671 | * |
||
672 | * @return \Wa72\HtmlPageDom\HtmlPageCrawler $this for chaining |
||
673 | * @api |
||
674 | */ |
||
675 | 1 | public function unwrap() |
|
676 | { |
||
677 | 1 | $parents = array(); |
|
678 | 1 | foreach($this as $i => $node) { |
|
679 | 1 | $parents[] = $node->parentNode; |
|
680 | } |
||
681 | |||
682 | 1 | self::create($parents)->unwrapInner(); |
|
683 | 1 | return $this; |
|
684 | } |
||
685 | |||
686 | /** |
||
687 | * Remove the matched elements, but promote the children to take their place. |
||
688 | * |
||
689 | * @return \Wa72\HtmlPageDom\HtmlPageCrawler $this for chaining |
||
690 | * @api |
||
691 | */ |
||
692 | 2 | public function unwrapInner() |
|
693 | { |
||
694 | 2 | foreach($this as $i => $node) { |
|
695 | 2 | if (!$node->parentNode instanceof \DOMElement) { |
|
696 | 1 | throw new \InvalidArgumentException('DOMElement does not have a parent DOMElement node.'); |
|
697 | } |
||
698 | |||
699 | /** @var \DOMNode[] $children */ |
||
700 | 2 | $children = iterator_to_array($node->childNodes); |
|
701 | 2 | foreach ($children as $child) { |
|
702 | 1 | $node->parentNode->insertBefore($child, $node); |
|
703 | } |
||
704 | |||
705 | 2 | $node->parentNode->removeChild($node); |
|
706 | } |
||
707 | 2 | } |
|
708 | |||
709 | |||
710 | /** |
||
711 | * Wrap an HTML structure around each element in the set of matched elements |
||
712 | * |
||
713 | * The HTML structure must contain only one root node, e.g.: |
||
714 | * Works: <div><div></div></div> |
||
715 | * Does not work: <div></div><div></div> |
||
716 | * |
||
717 | * @param string|HtmlPageCrawler|\DOMNode $wrappingElement |
||
718 | * @return HtmlPageCrawler $this for chaining |
||
719 | * @api |
||
720 | */ |
||
721 | 1 | public function wrap($wrappingElement) |
|
722 | { |
||
723 | 1 | $content = self::create($wrappingElement); |
|
724 | 1 | $newnodes = array(); |
|
725 | 1 | foreach ($this as $i => $node) { |
|
726 | /** @var \DOMNode $node */ |
||
727 | 1 | $newnode = $content->getNode(0); |
|
728 | /** @var \DOMNode $newnode */ |
||
729 | // $newnode = static::importNewnode($newnode, $node, $i); |
||
730 | 1 | if ($newnode->ownerDocument !== $node->ownerDocument) { |
|
731 | 1 | $newnode = $node->ownerDocument->importNode($newnode, true); |
|
732 | } else { |
||
733 | if ($i > 0) { |
||
734 | $newnode = $newnode->cloneNode(true); |
||
735 | } |
||
736 | } |
||
737 | 1 | $oldnode = $node->parentNode->replaceChild($newnode, $node); |
|
738 | 1 | while ($newnode->hasChildNodes()) { |
|
739 | 1 | $elementFound = false; |
|
740 | 1 | foreach ($newnode->childNodes as $child) { |
|
741 | 1 | if ($child instanceof \DOMElement) { |
|
742 | 1 | $newnode = $child; |
|
743 | 1 | $elementFound = true; |
|
744 | 1 | break; |
|
745 | } |
||
746 | } |
||
747 | 1 | if (!$elementFound) { |
|
748 | 1 | break; |
|
749 | } |
||
750 | } |
||
751 | 1 | $newnode->appendChild($oldnode); |
|
752 | 1 | $newnodes[] = $newnode; |
|
753 | } |
||
754 | 1 | $content->clear(); |
|
755 | 1 | $content->add($newnodes); |
|
756 | 1 | return $this; |
|
757 | } |
||
758 | |||
759 | /** |
||
760 | * Wrap an HTML structure around all elements in the set of matched elements. |
||
761 | * |
||
762 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $content |
||
763 | * @throws \LogicException |
||
764 | * @return \Wa72\HtmlPageDom\HtmlPageCrawler $this for chaining |
||
765 | * @api |
||
766 | */ |
||
767 | 1 | public function wrapAll($content) |
|
768 | { |
||
769 | 1 | $content = self::create($content); |
|
770 | 1 | $parent = $this->getNode(0)->parentNode; |
|
771 | 1 | foreach ($this as $i => $node) { |
|
772 | /** @var \DOMNode $node */ |
||
773 | 1 | if ($node->parentNode !== $parent) { |
|
774 | 1 | throw new \LogicException('Nodes to be wrapped with wrapAll() must all have the same parent'); |
|
775 | } |
||
776 | } |
||
777 | |||
778 | 1 | $newnode = $content->getNode(0); |
|
779 | /** @var \DOMNode $newnode */ |
||
780 | 1 | $newnode = static::importNewnode($newnode, $parent); |
|
781 | |||
782 | 1 | $newnode = $parent->insertBefore($newnode,$this->getNode(0)); |
|
783 | 1 | $content->clear(); |
|
784 | 1 | $content->add($newnode); |
|
785 | |||
786 | 1 | while ($newnode->hasChildNodes()) { |
|
787 | 1 | $elementFound = false; |
|
788 | 1 | foreach ($newnode->childNodes as $child) { |
|
789 | 1 | if ($child instanceof \DOMElement) { |
|
790 | 1 | $newnode = $child; |
|
791 | 1 | $elementFound = true; |
|
792 | 1 | break; |
|
793 | } |
||
794 | } |
||
795 | 1 | if (!$elementFound) { |
|
796 | break; |
||
797 | } |
||
798 | } |
||
799 | 1 | foreach ($this as $i => $node) { |
|
800 | /** @var \DOMNode $node */ |
||
801 | 1 | $newnode->appendChild($node); |
|
802 | } |
||
803 | 1 | return $this; |
|
804 | } |
||
805 | |||
806 | /** |
||
807 | * Wrap an HTML structure around the content of each element in the set of matched elements. |
||
808 | * |
||
809 | * @param string|HtmlPageCrawler|\DOMNode|\DOMNodeList $content |
||
810 | * @return \Wa72\HtmlPageDom\HtmlPageCrawler $this for chaining |
||
811 | * @api |
||
812 | */ |
||
813 | 1 | public function wrapInner($content) |
|
814 | { |
||
815 | 1 | foreach ($this as $i => $node) { |
|
816 | /** @var \DOMNode $node */ |
||
817 | 1 | self::create($node->childNodes)->wrapAll($content); |
|
818 | } |
||
819 | 1 | return $this; |
|
820 | } |
||
821 | |||
822 | /** |
||
823 | * Get the HTML code fragment of all elements and their contents. |
||
824 | * |
||
825 | * If the first node contains a complete HTML document return only |
||
826 | * the full code of this document. |
||
827 | * |
||
828 | * @return string HTML code (fragment) |
||
829 | * @api |
||
830 | */ |
||
831 | 8 | public function saveHTML() |
|
832 | { |
||
833 | 8 | if ($this->isHtmlDocument()) { |
|
834 | 1 | return $this->getDOMDocument()->saveHTML(); |
|
835 | } else { |
||
836 | 8 | $doc = new \DOMDocument('1.0', 'UTF-8'); |
|
837 | 8 | $root = $doc->appendChild($doc->createElement('_root')); |
|
838 | 8 | foreach ($this as $node) { |
|
839 | 8 | $root->appendChild($doc->importNode($node, true)); |
|
840 | } |
||
841 | 8 | $html = trim($doc->saveHTML()); |
|
842 | 8 | return preg_replace('@^<'.self::FRAGMENT_ROOT_TAGNAME.'[^>]*>|</'.self::FRAGMENT_ROOT_TAGNAME.'>$@', '', $html); |
|
843 | } |
||
844 | } |
||
845 | |||
846 | 4 | public function __toString() |
|
847 | { |
||
848 | 4 | return $this->saveHTML(); |
|
849 | } |
||
850 | |||
851 | /** |
||
852 | * checks whether the first node contains a complete html document |
||
853 | * (as opposed to a document fragment) |
||
854 | * |
||
855 | * @return boolean |
||
856 | */ |
||
857 | 8 | public function isHtmlDocument() |
|
858 | { |
||
859 | 8 | $node = $this->getNode(0); |
|
860 | 8 | if ($node instanceof \DOMElement |
|
861 | 8 | && $node->ownerDocument instanceof \DOMDocument |
|
862 | 8 | && $node->ownerDocument->documentElement === $node |
|
863 | 8 | && $node->nodeName == 'html' |
|
864 | ) { |
||
865 | 1 | return true; |
|
866 | } else { |
||
867 | 8 | return false; |
|
868 | } |
||
869 | } |
||
870 | |||
871 | /** |
||
872 | * get ownerDocument of the first element |
||
873 | * |
||
874 | * @return \DOMDocument|null |
||
875 | */ |
||
876 | 1 | public function getDOMDocument() |
|
877 | { |
||
878 | 1 | $node = $this->getNode(0); |
|
879 | 1 | $r = null; |
|
880 | 1 | if ($node instanceof \DOMElement |
|
881 | 1 | && $node->ownerDocument instanceof \DOMDocument |
|
882 | ) { |
||
883 | 1 | $r = $node->ownerDocument; |
|
884 | } |
||
885 | 1 | return $r; |
|
886 | } |
||
887 | |||
888 | /** |
||
889 | * Filters the list of nodes with a CSS selector. |
||
890 | * |
||
891 | * @param string $selector |
||
892 | * @return HtmlPageCrawler |
||
893 | */ |
||
894 | 7 | public function filter($selector) |
|
895 | { |
||
896 | 7 | return parent::filter($selector); |
|
897 | } |
||
898 | |||
899 | /** |
||
900 | * Filters the list of nodes with an XPath expression. |
||
901 | * |
||
902 | * @param string $xpath An XPath expression |
||
903 | * |
||
904 | * @return HtmlPageCrawler A new instance of Crawler with the filtered list of nodes |
||
905 | * |
||
906 | * @api |
||
907 | */ |
||
908 | 2 | public function filterXPath($xpath) |
|
909 | { |
||
910 | 2 | return parent::filterXPath($xpath); |
|
911 | } |
||
912 | |||
913 | /** |
||
914 | * Adds HTML/XML content to the HtmlPageCrawler object (but not to the DOM of an already attached node). |
||
915 | * |
||
916 | * Function overriden from Crawler because HTML fragments are always added as complete documents there |
||
917 | * |
||
918 | * |
||
919 | * @param string $content A string to parse as HTML/XML |
||
920 | * @param null|string $type The content type of the string |
||
921 | * |
||
922 | * @return null|void |
||
923 | */ |
||
924 | 17 | public function addContent($content, $type = null) |
|
925 | { |
||
926 | 17 | if (empty($type)) { |
|
927 | 17 | $type = 'text/html;charset=UTF-8'; |
|
928 | } |
||
929 | 17 | if (substr($type, 0, 9) == 'text/html' && !preg_match('/<html\b[^>]*>/i', $content)) { |
|
930 | // string contains no <html> Tag => no complete document but an HTML fragment! |
||
931 | 16 | $this->addHtmlFragment($content); |
|
932 | } else { |
||
933 | 2 | parent::addContent($content, $type); |
|
934 | } |
||
935 | 17 | } |
|
936 | |||
937 | 15 | public function addHtmlFragment($content, $charset = 'UTF-8') |
|
938 | { |
||
939 | 15 | $d = new \DOMDocument('1.0', $charset); |
|
940 | 15 | $d->preserveWhiteSpace = false; |
|
941 | 15 | $root = $d->appendChild($d->createElement(self::FRAGMENT_ROOT_TAGNAME)); |
|
942 | 15 | $bodynode = Helpers::getBodyNodeFromHtmlFragment($content, $charset); |
|
943 | 15 | foreach ($bodynode->childNodes as $child) { |
|
944 | 15 | $inode = $root->appendChild($d->importNode($child, true)); |
|
945 | 15 | if ($inode) { |
|
946 | 15 | $this->addNode($inode); |
|
947 | } |
||
948 | } |
||
949 | 15 | } |
|
950 | |||
951 | /** |
||
952 | * Adds a node to the current list of nodes. |
||
953 | * |
||
954 | * This method uses the appropriate specialized add*() method based |
||
955 | * on the type of the argument. |
||
956 | * |
||
957 | * Overwritten from parent to allow Crawler to be added |
||
958 | * |
||
959 | * @param null|\DOMNodeList|array|\DOMNode|Crawler $node A node |
||
960 | * |
||
961 | * @api |
||
962 | */ |
||
963 | 29 | public function add($node) |
|
964 | { |
||
965 | 29 | if ($node instanceof Crawler) { |
|
966 | 1 | foreach ($node as $childnode) { |
|
967 | 1 | $this->addNode($childnode); |
|
968 | } |
||
969 | } else { |
||
970 | 29 | parent::add($node); |
|
0 ignored issues
–
show
It seems like
$node defined by parameter $node on line 963 can also be of type array ; however, Symfony\Component\DomCrawler\Crawler::add() does only seem to accept object<DOMNodeList>|obje...t<DOMNode>>|string|null , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
971 | } |
||
972 | 29 | } |
|
973 | |||
974 | /** |
||
975 | * @param \DOMNode $newnode |
||
976 | * @param \DOMNode $referencenode |
||
977 | * @param int $clone |
||
978 | * @return \DOMNode |
||
979 | */ |
||
980 | 6 | protected static function importNewnode(\DOMNode $newnode, \DOMNode $referencenode, $clone = 0) { |
|
981 | 6 | if ($newnode->ownerDocument !== $referencenode->ownerDocument) { |
|
982 | 5 | $referencenode->ownerDocument->preserveWhiteSpace = false; |
|
983 | 5 | $newnode = $referencenode->ownerDocument->importNode($newnode, true); |
|
984 | } else { |
||
985 | 2 | if ($clone > 0) { |
|
986 | $newnode = $newnode->cloneNode(true); |
||
987 | } |
||
988 | } |
||
989 | 6 | return $newnode; |
|
990 | } |
||
991 | |||
992 | // /** |
||
993 | // * Checks whether the first node in the set is disconnected (has no parent node) |
||
994 | // * |
||
995 | // * @return bool |
||
996 | // */ |
||
997 | // public function isDisconnected() |
||
998 | // { |
||
999 | // $parent = $this->getNode(0)->parentNode; |
||
1000 | // return ($parent == null || $parent->tagName == self::FRAGMENT_ROOT_TAGNAME); |
||
1001 | // } |
||
1002 | |||
1003 | 1 | public function __get($name) |
|
1004 | { |
||
1005 | switch ($name) { |
||
1006 | 1 | case 'count': |
|
1007 | 1 | case 'length': |
|
1008 | 1 | return count($this); |
|
1009 | } |
||
1010 | 1 | throw new \Exception('No such property ' . $name); |
|
1011 | } |
||
1012 | } |
||
1013 |
This check looks for a call to a parent method whose name is different than the method from which it is called.
Consider the following code:
The
getFirstName()
method in theSon
calls the wrong method in the parent class.