Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
CRAP | |
0.00% |
0 / 1 |
NodeData | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
132 | |
0.00% |
0 / 1 |
cloneNodeData | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
132 |
1 | <?php |
2 | declare( strict_types = 1 ); |
3 | |
4 | namespace Wikimedia\Parsoid\NodeData; |
5 | |
6 | use Wikimedia\Parsoid\DOM\Node; |
7 | use Wikimedia\Parsoid\Utils\DOMCompat; |
8 | use Wikimedia\Parsoid\Utils\DOMUtils; |
9 | use Wikimedia\Parsoid\Utils\Utils; |
10 | |
11 | // phpcs:disable MediaWiki.Commenting.PropertyDocumentation.ObjectTypeHintVar |
12 | |
13 | /** |
14 | * This object stores data associated with a single DOM node. |
15 | * |
16 | * Using undeclared properties reduces memory usage and CPU time if the |
17 | * property is null in more than about 75% of instances. There are typically |
18 | * a very large number of NodeData objects, so this optimisation is worthwhile. |
19 | * |
20 | * @property object|null $parsoid_diff |
21 | * @property object|null $mw_variant |
22 | * @property int|null $storedId |
23 | * @property DataMwI18n|null $i18n |
24 | */ |
25 | #[\AllowDynamicProperties] |
26 | class NodeData { |
27 | /** |
28 | * @var DataParsoid|null The unserialized data-parsoid attribute |
29 | */ |
30 | public $parsoid; |
31 | |
32 | /** |
33 | * @var object|null The unserialized data-mw attribute |
34 | */ |
35 | public $mw; |
36 | |
37 | /** |
38 | * Deep clone this object |
39 | * If $stripSealedFragments is true, sealed DOMFragment included in expanded attributes are deleted in the |
40 | * clone. |
41 | * @param bool $stripSealedFragments |
42 | * @return self |
43 | */ |
44 | public function cloneNodeData( bool $stripSealedFragments = false ): self { |
45 | $cloneableData = get_object_vars( $this ); |
46 | // Don't clone $this->parsoid because it has a custom clone method |
47 | unset( $cloneableData['parsoid'] ); |
48 | // Don't clone storedId because it doesn't need it |
49 | unset( $cloneableData['storedId'] ); |
50 | // Deep clone everything else |
51 | $cloneableData = Utils::clone( $cloneableData ); |
52 | $nd = clone $this; |
53 | if ( $nd->parsoid ) { |
54 | $nd->parsoid = $nd->parsoid->clone(); |
55 | } |
56 | // Avoid cloning sealed DOMFragments that may occur in expanded attributes |
57 | if ( $nd->mw && $stripSealedFragments && is_array( $nd->mw->attribs ) ) { |
58 | foreach ( $nd->mw->attribs as $attr ) { |
59 | foreach ( $attr as $v ) { |
60 | if ( isset( $v->html ) && str_contains( $v->html, 'mw:DOMFragment/sealed' ) ) { |
61 | $doc = DOMUtils::parseHTML( $v->html ); |
62 | DOMUtils::visitDOM( $doc, static function ( Node $node ) { |
63 | if ( |
64 | DOMUtils::matchTypeOf( $node, '#^mw:DOMFragment/sealed/\w+$#D' ) |
65 | ) { |
66 | DOMCompat::getParentElement( $node )->removeChild( $node ); |
67 | } |
68 | } ); |
69 | $v->html = DOMCompat::getInnerHTML( DOMCompat::getBody( $doc ) ); |
70 | } |
71 | } |
72 | } |
73 | } |
74 | foreach ( $cloneableData as $key => $value ) { |
75 | $nd->$key = $value; |
76 | } |
77 | return $nd; |
78 | } |
79 | } |