Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
DataBag
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 10
272
0.00% covered (danger)
0.00%
0 / 1
 getObject
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 stashObject
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 updateCountersFromPageBundle
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 updateCountersInPageBundle
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 counterValue
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 newAboutId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 seenAboutId
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 newAnnotationId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 seenAnnotationId
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 __clone
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2declare( strict_types = 1 );
3
4namespace Wikimedia\Parsoid\NodeData;
5
6use Wikimedia\Parsoid\Core\BasePageBundle;
7use Wikimedia\Parsoid\Utils\CounterType;
8
9class DataBag {
10    /**
11     * @var NodeData[] A map of node data-object-id ids to data objects.
12     * This map is used during DOM processing to avoid having to repeatedly
13     * json-parse/json-serialize data-parsoid and data-mw attributes.
14     * This map is initialized when a DOM is created/parsed/refreshed.
15     */
16    private array $dataObject = [];
17
18    /** An id counter for this document used for the dataObject map */
19    private int $nodeId = 0;
20
21    /** An id counter for this document used for about IDs. */
22    private int $aboutId = 1;
23
24    /** An id counter for this document used for annotation IDs. */
25    private int $annotationId = 0;
26
27    /**
28     * This is the input page bundle for an input doc available in pagebundle form.
29     * It is read-only and hence does not need to be deep-cloned. During eager
30     * loading of the doc's data-* attributes, this is useless after loading completes.
31     * But, during lazy loading, unloaded data will be transferred over to the
32     * output pagebundle during serialization, and so this pagebundle might be active
33     * and used till the very end of the request.
34     */
35    public ?BasePageBundle $inputPageBundle = null;
36
37    /**
38     * Should every Parsoid-generated node be serialized with a data-parsoid attribute?
39     * This property is set per-transformation (whether wt2html, html2wt, or html2html)
40     * and as such, we record it here in the top-level document's databag.
41     * This is true everywhere except during wt2html transforms and is hence safe
42     * to default to false.
43     */
44    public bool $serializeNewEmptyDp = false;
45
46    /**
47     * Track whether or not data attributes have been loaded for this document.
48     * See DOMDataUtils::prepareAndLoadDoc(). This flag might eventually be removed.
49     */
50    public bool $loaded = false;
51
52    /**
53     * FIXME: Figure out a decent interface for updating these depths
54     * without needing to import the various util files.
55     *
56     * Map of start/end meta tag tree depths keyed by about id
57     */
58    public array $transclusionMetaTagDepthMap = [];
59
60    /**
61     * Get the data object for the node with data-object-id 'nodeId'.
62     * This will return null if a non-existent nodeId is provided.
63     *
64     * @param int $nodeId
65     * @return NodeData|null
66     */
67    public function getObject( int $nodeId ): ?NodeData {
68        return $this->dataObject[$nodeId] ?? null;
69    }
70
71    /**
72     * Stash the data and return an id for retrieving it later
73     */
74    public function stashObject( NodeData $data ): int {
75        $nodeId = $this->nodeId++;
76        $this->dataObject[$nodeId] = $data;
77        return $nodeId;
78    }
79
80    public function updateCountersFromPageBundle( BasePageBundle $pb ): void {
81        if ( $pb->counters !== null ) {
82            $this->annotationId = max( $this->annotationId, $pb->counters['annotation'] ?? -1 );
83            $this->aboutId = max( $this->aboutId, $pb->counters['transclusion'] ?? -1 );
84        }
85    }
86
87    public function updateCountersInPageBundle( BasePageBundle $pb ): void {
88        $pb->counters['annotation'] = $this->counterValue( CounterType::ANNOTATION_ABOUT );
89        $pb->counters['transclusion'] = $this->counterValue( CounterType::TRANSCLUSION_ABOUT );
90    }
91
92    public function counterValue( CounterType $type ): int {
93        return match ( $type ) {
94            CounterType::ANNOTATION_ABOUT => $this->annotationId,
95            CounterType::TRANSCLUSION_ABOUT => $this->aboutId,
96            // Id counter isn't stored in the DataBag class
97            CounterType::NODE_DATA_ID => throw new \LogicException( "Not stored here" )
98        };
99    }
100
101    public function newAboutId(): string {
102        return CounterType::TRANSCLUSION_ABOUT->counterToId( $this->aboutId++ );
103    }
104
105    public function seenAboutId( string $id ): void {
106        $val = CounterType::TRANSCLUSION_ABOUT->idToCounter( $id );
107        if ( $val !== null ) {
108            $val = intval( $val );
109            if ( $this->aboutId <= $val ) {
110                $this->aboutId = $val + 1;
111            }
112        }
113    }
114
115    public function newAnnotationId(): string {
116        return CounterType::ANNOTATION_ABOUT->counterToId( $this->annotationId++ );
117    }
118
119    public function seenAnnotationId( string $id ): void {
120        $val = CounterType::ANNOTATION_ABOUT->idToCounter( $id );
121        if ( $val !== null ) {
122            $val = intval( $val );
123            if ( $this->annotationId <= $val ) {
124                $this->annotationId = $val + 1;
125            }
126        }
127    }
128
129    public function __clone() {
130        // The only thing which needs to be deep cloned is $dataObject
131        foreach ( $this->dataObject as $id => &$nodeData ) {
132            $nodeData = clone $nodeData;
133        }
134    }
135}