ManipulationTrait   F
last analyzed

Complexity

Total Complexity 90

Size/Duplication

Total Lines 730
Duplicated Lines 0 %

Test Coverage

Coverage 96.55%

Importance

Changes 15
Bugs 0 Features 0
Metric Value
wmc 90
eloc 221
c 15
b 0
f 0
dl 0
loc 730
ccs 224
cts 232
cp 0.9655
rs 2

42 Methods

Rating   Name   Duplication   Size   Complexity  
A __call() 0 6 2
A inputAsFirstNode() 0 4 1
A inputPrepareAsTraversable() 0 17 5
A inputAsNodeList() 0 18 5
A __toString() 0 2 1
A _empty() 0 6 1
A create() 0 2 1
A removeAttr() 0 8 2
A _clone() 0 8 1
A manipulateNodesWithInput() 0 18 2
A nodesFromHtml() 0 7 1
A getText() 0 4 1
A _prepareWrapStack() 0 11 2
A getOuterHtml() 0 10 2
A addClass() 0 4 1
A hasAttr() 0 8 2
A html() 0 5 2
A wrapWithInputByCallback() 0 15 3
A getHtml() 0 10 2
A detach() 0 18 3
A appendTo() 0 10 3
A prependTo() 0 10 3
A setAttr() 0 8 2
A _getFirstChildWrapStack() 0 13 2
A hasClass() 0 12 2
A attr() 0 5 2
A text() 0 5 2
B _pushAttrValue() 0 29 8
A removeClass() 0 4 1
A getAttr() 0 8 2
A unwrap() 0 15 1
A precede() 0 8 2
A wrapInner() 0 15 2
A destroy() 0 4 1
A wrapAll() 0 26 4
A setText() 0 14 2
A follow() 0 12 3
A appendWith() 0 8 2
A substituteWith() 0 8 2
A wrap() 0 13 1
A prependWith() 0 8 2
A setHtml() 0 10 1

How to fix   Complexity   

Complex Class

Complex classes like ManipulationTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ManipulationTrait, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types=1);
2
3
namespace DOMWrap\Traits;
4
5
use DOMWrap\{
6
    Text,
7
    Element,
8
    NodeList
9
};
10
11
/**
12
 * Manipulation Trait
13
 *
14
 * @package DOMWrap\Traits
15
 * @license http://opensource.org/licenses/BSD-3-Clause BSD 3 Clause
16
 */
17
trait ManipulationTrait
18
{
19
    /**
20
     * Magic method - Trap function names using reserved keyword (empty, clone, etc..)
21
     *
22
     * @param string $name
23
     * @param array $arguments
24
     *
25
     * @return mixed
26
     */
27 8
    public function __call(string $name, array $arguments) {
28 8
        if (!method_exists($this, '_' . $name)) {
29 1
            throw new \BadMethodCallException("Call to undefined method " . get_class($this) . '::' . $name . "()");
30
        }
31
32 7
        return call_user_func_array([$this, '_' . $name], $arguments);
33
    }
34
35
    /**
36
     * @return string
37
     */
38
    public function __toString(): string {
39
        return $this->getOuterHtml(true);
40 61
    }
41 61
42 34
    /**
43 50
     * @param string|NodeList|\DOMNode $input
44 45
     *
45 13
     * @return iterable
46 13
     */
47
    protected function inputPrepareAsTraversable($input): iterable {
48
        if ($input instanceof \DOMNode) {
49
            // Handle raw \DOMNode elements and 'convert' them into their DOMWrap/* counterpart
50
            if (!method_exists($input, 'inputPrepareAsTraversable')) {
51 61
                $input = $this->document()->importNode($input, true);
0 ignored issues
show
Bug introduced by
The method document() does not exist on DOMWrap\Traits\ManipulationTrait. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

51
                $input = $this->/** @scrutinizer ignore-call */ document()->importNode($input, true);
Loading history...
52
            }
53
54
            $nodes = [$input];
55
        } else if (is_string($input)) {
56
            $nodes = $this->nodesFromHtml($input);
57
        } else if (is_iterable($input)) {
58
            $nodes = $input;
59 61
        } else {
60 61
            throw new \InvalidArgumentException();
61
        }
62 61
63
        return $nodes;
64 61
    }
65 60
66 49
    /**
67
     * @param string|NodeList|\DOMNode $input
68 60
     * @param bool $cloneForManipulate
69
     *
70
     * @return NodeList
71
     */
72 61
    protected function inputAsNodeList($input, $cloneForManipulate = true): NodeList {
73
        $nodes = $this->inputPrepareAsTraversable($input);
74
75
        $newNodes = $this->newNodeList();
0 ignored issues
show
Bug introduced by
The method newNodeList() does not exist on DOMWrap\Traits\ManipulationTrait. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

75
        /** @scrutinizer ignore-call */ 
76
        $newNodes = $this->newNodeList();
Loading history...
76
77
        foreach ($nodes as $node) {
78
            if ($node->document() !== $this->document()) {
79
                 $node = $this->document()->importNode($node, true);
80 22
            }
81 22
82
            if ($cloneForManipulate && $node->parentNode !== null) {
83 22
                $node = $node->cloneNode(true);
84
            }
85
86
            $newNodes[] = $node;
87
        }
88
89
        return $newNodes;
90
    }
91 45
92 45
    /**
93 45
     * @param string|NodeList|\DOMNode $input
94 45
     *
95
     * @return \DOMNode|null
96 45
     */
97
    protected function inputAsFirstNode($input): ?\DOMNode {
98
        $nodes = $this->inputAsNodeList($input);
99
100
        return $nodes->findXPath('self::*')->first();
101
    }
102
103
    /**
104
     * @param string $html
105
     *
106 53
     * @return NodeList
107 51
     */
108
    protected function nodesFromHtml($html): NodeList {
109 51
        $class = get_class($this->document());
110 6
        $doc = new $class();
111
        $doc->setEncoding($this->document()->getEncoding());
112
        $nodes = $doc->html($html)->find('body > *');
113 51
114
        return $nodes;
115 51
    }
116 53
117
    /**
118 53
     * @param string|NodeList|\DOMNode|callable $input
119
     * @param callable $callback
120
     *
121
     * @return self
122
     */
123
    protected function manipulateNodesWithInput($input, callable $callback): self {
124
        $this->collection()->each(function($node, $index) use ($input, $callback) {
0 ignored issues
show
Bug introduced by
The method collection() does not exist on DOMWrap\Traits\ManipulationTrait. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

124
        $this->/** @scrutinizer ignore-call */ 
125
               collection()->each(function($node, $index) use ($input, $callback) {
Loading history...
125
            $html = $input;
126 40
127 40
            /*if ($input instanceof \DOMNode) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
128 1
                if ($input->parentNode !== null) {
129
                    $html = $input->cloneNode(true);
130 39
                }
131
            } else*/if (is_callable($input)) {
132
                $html = $input($node, $index);
133 40
            }
134
135 40
            $newNodes = $this->inputAsNodeList($html);
136 36
137 36
            $callback($node, $newNodes);
138
        });
139 40
140
        return $this;
141 40
    }
142
143 40
    /**
144
     * @param string|null $selector
145
     *
146
     * @return NodeList
147
     */
148
    public function detach(string $selector = null): NodeList {
149
        if (!is_null($selector)) {
150
            $nodes = $this->find($selector, 'self::');
0 ignored issues
show
Bug introduced by
The method find() does not exist on DOMWrap\Traits\ManipulationTrait. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

150
            /** @scrutinizer ignore-call */ 
151
            $nodes = $this->find($selector, 'self::');
Loading history...
151 35
        } else {
152 35
            $nodes = $this->collection();
153
        }
154 35
155
        $nodeList = $this->newNodeList();
156
157
        $nodes->each(function($node) use($nodeList) {
158
            if ($node->parent() instanceof \DOMNode) {
159
                $nodeList[] = $node->parent()->removeChild($node);
160
            }
161
        });
162
163 3
        $nodes->fromArray([]);
164 3
165 3
        return $nodeList;
166
    }
167 3
168
    /**
169 3
     * @param string|null $selector
170
     *
171
     * @return self
172
     */
173
    public function destroy(string $selector = null): self {
174
        $this->detach($selector);
175
176
        return $this;
177 14
    }
178 14
179 9
    /**
180
     * @param string|NodeList|\DOMNode|callable $input
181 5
     *
182
     * @return self
183
     */
184
    public function substituteWith($input): self {
185
        $this->manipulateNodesWithInput($input, function($node, $newNodes) {
186
            foreach ($newNodes as $newNode) {
187
                $node->parent()->replaceChild($newNode, $node);
188
            }
189 13
        });
190 13
191 13
        return $this;
192
    }
193
194
    /**
195
     * @param string|NodeList|\DOMNode|callable $input
196
     *
197
     * @return string|self
198
     */
199 5
    public function text($input = null) {
200 5
        if (is_null($input)) {
201 4
            return $this->getText();
202
        } else {
203
            return $this->setText($input);
204 5
        }
205
    }
206 4
207
    /**
208
     * @return string
209 4
     */
210 5
    public function getText(): string {
211
        return (string)$this->collection()->reduce(function($carry, $node) {
212 5
            return $carry . $node->textContent;
213
        }, '');
214
    }
215
216
    /**
217
     * @param string|NodeList|\DOMNode|callable $input
218
     *
219
     * @return self
220
     */
221 12
    public function setText($input): self {
222 12
        if (is_string($input)) {
223 12
            $input = new Text($input);
224
        }
225 12
226
        $this->manipulateNodesWithInput($input, function($node, $newNodes) {
227 12
            // Remove old contents from the current node.
228
            $node->contents()->destroy();
229
230
            // Add new contents in it's place.
231
            $node->appendWith(new Text($newNodes->getText()));
232
        });
233
234
        return $this;
235
    }
236 12
237 12
    /**
238 12
     * @param string|NodeList|\DOMNode|callable $input
239 12
     *
240
     * @return self
241 12
     */
242
    public function precede($input): self {
243
        $this->manipulateNodesWithInput($input, function($node, $newNodes) {
244 12
            foreach ($newNodes as $newNode) {
245
                $node->parent()->insertBefore($newNode, $node);
246 12
            }
247
        });
248
249
        return $this;
250
    }
251
252
    /**
253
     * @param string|NodeList|\DOMNode|callable $input
254
     *
255 4
     * @return self
256 4
     */
257 4
    public function follow($input): self {
258
        $this->manipulateNodesWithInput($input, function($node, $newNodes) {
259 4
            foreach ($newNodes as $newNode) {
260
                if (is_null($node->following())) {
261 4
                    $node->parent()->appendChild($newNode);
262
                } else {
263
                    $node->parent()->insertBefore($newNode, $node->following());
264
                }
265
            }
266
        });
267
268
        return $this;
269
    }
270 33
271 33
    /**
272 33
     * @param string|NodeList|\DOMNode|callable $input
273
     *
274 33
     * @return self
275
     */
276 33
    public function prependWith($input): self {
277
        $this->manipulateNodesWithInput($input, function($node, $newNodes) {
278
            foreach ($newNodes as $newNode) {
279
                $node->insertBefore($newNode, $node->contents()->first());
280
            }
281
        });
282
283 4
        return $this;
284 3
    }
285 4
286
    /**
287 4
     * @param string|NodeList|\DOMNode|callable $input
288
     *
289
     * @return self
290
     */
291
    public function appendWith($input): self {
292
        $this->manipulateNodesWithInput($input, function($node, $newNodes) {
293 3
            foreach ($newNodes as $newNode) {
294 3
                $node->appendChild($newNode);
295
            }
296 3
        });
297 3
298 3
        return $this;
299
    }
300 3
301
    /**
302
     * @param string|NodeList|\DOMNode $selector
303
     *
304
     * @return self
305
     */
306
    public function prependTo($selector): self {
307
        if ($selector instanceof \DOMNode || $selector instanceof NodeList) {
308
            $nodes = $this->inputAsNodeList($selector);
309 5
        } else {
310 4
            $nodes = $this->document()->find($selector);
311 4
        }
312
313 5
        $nodes->prependWith($this);
314
315 5
        return $this;
316
    }
317
318
    /**
319
     * @param string|NodeList|\DOMNode $selector
320
     *
321
     * @return self
322
     */
323
    public function appendTo($selector): self {
324
        if ($selector instanceof \DOMNode || $selector instanceof NodeList) {
325
            $nodes = $this->inputAsNodeList($selector);
326
        } else {
327
            $nodes = $this->document()->find($selector);
328
        }
329
330
        $nodes->appendWith($this);
331
332
        return $this;
333
    }
334
335
    /**
336
     * @return self
337
     */
338
    public function _empty(): self {
339
        $this->collection()->each(function($node) {
340 18
            $node->contents()->destroy();
341 18
        });
342
343 18
        return $this;
344 1
    }
345
346
    /**
347 17
     * @return NodeList|\DOMNode
348
     */
349 17
    public function _clone() {
350 6
        $clonedNodes = $this->newNodeList();
351
352
        $this->collection()->each(function($node) use($clonedNodes) {
353 13
            $clonedNodes[] = $node->cloneNode(true);
354
        });
355
356
        return $this->result($clonedNodes);
0 ignored issues
show
Bug introduced by
The method result() does not exist on DOMWrap\Traits\ManipulationTrait. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

356
        return $this->/** @scrutinizer ignore-call */ result($clonedNodes);
Loading history...
357
    }
358
359
    /**
360
     * @param string $name
361
     *
362
     * @return self
363
     */
364
    public function removeAttr(string $name): self {
365 5
        $this->collection()->each(function($node) use($name) {
366 3
            if ($node instanceof \DOMElement) {
367 3
                $node->removeAttribute($name);
368
            }
369 5
        });
370
371 5
        return $this;
372
    }
373
374
    /**
375
     * @param string $name
376
     *
377
     * @return bool
378
     */
379
    public function hasAttr(string $name): bool {
380 17
        return (bool)$this->collection()->reduce(function($carry, $node) use ($name) {
381 17
            if ($node->hasAttribute($name)) {
382 12
                return true;
383
            }
384 5
385
            return $carry;
386
        }, false);
387
    }
388
389
    /**
390
     * @internal
391
     *
392
     * @param string $name
393
     *
394
     * @return string
395
     */
396 15
    public function getAttr(string $name): string {
397 15
        $node = $this->collection()->first();
398 15
399
        if (!($node instanceof \DOMElement)) {
400 15
            return '';
401 2
        }
402
403
        return $node->getAttribute($name);
404
    }
405 15
406 15
    /**
407 10
     * @internal
408
     *
409
     * @param string $name
410 11
     * @param mixed $value
411 15
     *
412
     * @return self
413
     */
414 15
    public function setAttr(string $name, $value): self {
415 7
        $this->collection()->each(function($node) use($name, $value) {
416
            if ($node instanceof \DOMElement) {
417
                $node->setAttribute($name, (string)$value);
418
            }
419
        });
420
421
        return $this;
422 15
    }
423 13
424
    /**
425
     * @param string $name
426 15
     * @param mixed $value
427 15
     *
428
     * @return self|string
429
     */
430
    public function attr(string $name, $value = null) {
431
        if (is_null($value)) {
432
            return $this->getAttr($name);
433
        } else {
434 7
            return $this->setAttr($name, $value);
435 7
        }
436
    }
437 7
438
    /**
439
     * @internal
440
     *
441
     * @param string $name
442
     * @param string|callable $value
443
     * @param bool $addValue
444
     */
445 8
    protected function _pushAttrValue(string $name, $value, bool $addValue = false): void {
446 8
        $this->collection()->each(function($node, $index) use($name, $value, $addValue) {
447
            if ($node instanceof \DOMElement) {
448 8
                $attr = $node->getAttribute($name);
449
450
                if (is_callable($value)) {
451
                    $value = $value($node, $index, $attr);
452
                }
453
454
                // Remove any existing instances of the value, or empty values.
455
                $values = array_filter(explode(' ', $attr), function($_value) use($value) {
456
                    if (strcasecmp($_value, $value) == 0 || empty($_value)) {
457 6
                        return false;
458 6
                    }
459
460 6
                    return true;
461 6
                });
462 2
463
                // If required add attr value to array
464
                if ($addValue) {
465 6
                    $values[] = $value;
466 6
                }
467 6
468
                // Set the attr if we either have values, or the attr already
469
                //  existed (we might be removing classes).
470
                //
471
                // Don't set the attr if it doesn't already exist.
472
                if (!empty($values) || $node->hasAttribute($name)) {
473
                    $node->setAttribute($name, implode(' ', $values));
474
                }
475 21
            }
476 21
        });
477
    }
478
479
    /**
480 21
     * @param string|callable $class
481
     *
482
     * @return self
483 21
     */
484 21
    public function addClass($class): self {
485
        $this->_pushAttrValue('class', $class, true);
486
487 21
        return $this;
488
    }
489
490
    /**
491
     * @param string|callable $class
492
     *
493
     * @return self
494
     */
495 21
    public function removeClass($class): self {
496
        $this->_pushAttrValue('class', $class);
497
498 21
        return $this;
499
    }
500
501 21
    /**
502 21
     * @param string $class
503
     *
504
     * @return bool
505 21
     */
506
    public function hasClass(string $class): bool {
507
        return (bool)$this->collection()->reduce(function($carry, $node) use ($class) {
508
            $attr = $node->getAttr('class');
509
510
            return array_reduce(explode(' ', (string)$attr), function($carry, $item) use ($class) {
511
                if (strcasecmp($item, $class) == 0) {
512
                    return true;
513 18
                }
514 16
515
                return $carry;
516 16
            }, false);
517
        }, false);
518
    }
519
520 16
    /**
521
     * @param Element $node
522 16
     *
523
     * @return \SplStack
524 16
     */
525
    protected function _getFirstChildWrapStack(Element $node): \SplStack {
526 16
        $stack = new \SplStack;
527
528 18
        do {
529 18
            // Push our current node onto the stack
530
            $stack->push($node);
531
532
            // Get the first element child node
533
            $node = $node->children()->first();
534
        } while ($node instanceof Element);
535
536
        // Get the top most node.
537 9
        return $stack;
538 8
    }
539
540 8
    /**
541
     * @param Element $node
542
     *
543 8
     * @return \SplStack
544
     */
545
    protected function _prepareWrapStack(Element $node): \SplStack {
546
        // Generate a stack (root to leaf) of the wrapper.
547 8
        // Includes only first element nodes / first element children.
548 9
        $stackNodes = $this->_getFirstChildWrapStack($node);
549
550 9
        // Only using the first element, remove any siblings.
551
        foreach ($stackNodes as $stackNode) {
552
            $stackNode->siblings()->destroy();
553
        }
554
555
        return $stackNodes;
556
    }
557
558
    /**
559 9
     * @param string|NodeList|\DOMNode|callable $input
560
     * @param callable $callback
561 8
     */
562
    protected function wrapWithInputByCallback($input, callable $callback): void {
563
        $this->collection()->each(function($node, $index) use ($input, $callback) {
564 8
            $html = $input;
565
566
            if (is_callable($input)) {
567 8
                $html = $input($node, $index);
568 9
            }
569
570 9
            $inputNode = $this->inputAsFirstNode($html);
571
572
            if ($inputNode instanceof Element) {
573
                // Pre-process wrapper into a stack of first element nodes.
574
                $stackNodes = $this->_prepareWrapStack($inputNode);
575
576
                $callback($node, $stackNodes);
577
            }
578 7
        });
579 7
    }
580 1
581
    /**
582
     * @param string|NodeList|\DOMNode|callable $input
583 6
     *
584
     * @return self
585
     */
586
    public function wrapInner($input): self {
587 6
        $this->wrapWithInputByCallback($input, function($node, $stackNodes) {
588
            foreach ($node->contents() as $child) {
589 6
                // Remove child from the current node
590 1
                $oldChild = $child->detach()->first();
591
592
                // Add it back as a child of the top (leaf) node on the stack
593 5
                $stackNodes->top()->appendWith($oldChild);
594
            }
595
596 5
            // Add the bottom (root) node on the stack
597
            $node->appendWith($stackNodes->bottom());
598 5
        });
599
600 5
        return $this;
601 5
    }
602
603 5
    /**
604
     * @param string|NodeList|\DOMNode|callable $input
605
     *
606
     * @return self
607
     */
608
    public function wrap($input): self {
609
        $this->wrapWithInputByCallback($input, function($node, $stackNodes) {
610 4
            // Add the new bottom (root) node after the current node
611 3
            $node->follow($stackNodes->bottom());
612
613
            // Remove the current node
614 3
            $oldNode = $node->detach()->first();
615 3
616
            // Add the 'current node' back inside the new top (leaf) node.
617 3
            $stackNodes->top()->appendWith($oldNode);
618 3
        });
619
620 3
        return $this;
621 4
    }
622
623 4
    /**
624
     * @param string|NodeList|\DOMNode|callable $input
625
     *
626
     * @return self
627
     */
628
    public function wrapAll($input): self {
629 2
        if (!$this->collection()->count()) {
630 2
            return $this;
631 2
        }
632
633
        if (is_callable($input)) {
634
            $input = $input($this->collection()->first());
635
        }
636
637
        $inputNode = $this->inputAsFirstNode($input);
638
639 1
        if (!($inputNode instanceof Element)) {
640 1
            return $this;
641 1
        }
642
643
        $stackNodes = $this->_prepareWrapStack($inputNode);
644
645
        // Add the new bottom (root) node before the first matched node
646
        $this->collection()->first()->precede($stackNodes->bottom());
647
648
        $this->collection()->each(function($node) use ($stackNodes) {
649
            // Detach and add node back inside the new wrappers top (leaf) node.
650 5
            $stackNodes->top()->appendWith($node->detach());
651
        });
652 4
653
        return $this;
654
    }
655 4
656 5
    /**
657
     * @return self
658 5
     */
659
    public function unwrap(): self {
660
        $this->collection()->each(function($node) {
661
            $parent = $node->parent();
662
663
            // Replace parent node (the one we're unwrapping) with it's children.
664
            $parent->contents()->each(function($childNode) use($parent) {
665
                $oldChildNode = $childNode->detach()->first();
666 140
667 140
                $parent->precede($oldChildNode);
668 2
            });
669
670 140
            $parent->destroy();
671
        });
672
673
        return $this;
674
    }
675
676
    /**
677
     * @param int $isIncludeAll
678
     *
679
     * @return string
680
     */
681
    public function getOuterHtml(bool $isIncludeAll = false): string {
682
        $nodes = $this->collection();
683
684
        if (!$isIncludeAll) {
685
            $nodes = $this->newNodeList([$nodes->first()]);
686
        }
687
688
        return $nodes->reduce(function($carry, $node) {
689
            return $carry . $this->document()->saveHTML($node);
690
        }, '');
691
    }
692
693
    /**
694
     * @param int $isIncludeAll
695
     *
696
     * @return string
697
     */
698
    public function getHtml(bool $isIncludeAll = false): string {
699
        $nodes = $this->collection();
700
701
        if (!$isIncludeAll) {
702
            $nodes = $this->newNodeList([$nodes->first()]);
703
        }
704
705
        return $nodes->contents()->reduce(function($carry, $node) {
706
            return $carry . $this->document()->saveHTML($node);
707
        }, '');
708
    }
709
710
    /**
711
     * @param string|NodeList|\DOMNode|callable $input
712
     *
713
     * @return self
714
     */
715
    public function setHtml($input): self {
716
        $this->manipulateNodesWithInput($input, function($node, $newNodes) {
717
            // Remove old contents from the current node.
718
            $node->contents()->destroy();
719
720
            // Add new contents in it's place.
721
            $node->appendWith($newNodes);
722
        });
723
724
        return $this;
725
    }
726
727
    /**
728
     * @param string|NodeList|\DOMNode|callable $input
729
     *
730
     * @return string|self
731
     */
732
    public function html($input = null) {
733
        if (is_null($input)) {
734
            return $this->getHtml();
735
        } else {
736
            return $this->setHtml($input);
737
        }
738
    }
739
740
    /**
741
     * @param string|NodeList|\DOMNode $input
742
     *
743
     * @return NodeList
744
     */
745
    public function create($input): NodeList {
746
        return $this->inputAsNodeList($input);
747
    }
748
}