Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
40.00% covered (danger)
40.00%
6 / 15
25.00% covered (danger)
25.00%
1 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ContentDOMTransformStage
40.00% covered (danger)
40.00%
6 / 15
25.00% covered (danger)
25.00%
1 / 4
21.82
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFragmentsToTransform
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 transform
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 transformDOM
n/a
0 / 0
n/a
0 / 0
0
 createElement
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\OutputTransform;
5
6use MediaWiki\Config\ServiceOptions;
7use MediaWiki\Parser\ContentHolder;
8use MediaWiki\Parser\ParserOptions;
9use MediaWiki\Parser\ParserOutput;
10use Psr\Log\LoggerInterface;
11use Wikimedia\Parsoid\DOM\Document;
12use Wikimedia\Parsoid\DOM\DocumentFragment;
13use Wikimedia\Parsoid\DOM\Element;
14use Wikimedia\Parsoid\DOM\Node;
15use Wikimedia\Parsoid\Utils\DOMCompat;
16
17/**
18 * OutputTransformStages that modify the content as a HTML DOM tree.
19 *
20 * Subclasses are expected to implement ::transformDOM() to mutate the
21 * DOM-structured content as a Document in-place.
22 *
23 * @internal
24 */
25abstract class ContentDOMTransformStage extends OutputTransformStage
26    implements DOMTransformStage {
27
28    public function __construct(
29        ServiceOptions $options,
30        LoggerInterface $logger,
31        private readonly bool $transformBodyOnly,
32    ) {
33        parent::__construct( $options, $logger );
34    }
35
36    /**
37     * Override this method if you need more control over which fragments
38     * should be transformed.
39     */
40    protected function getFragmentsToTransform( ParserOutput $po, ParserOptions $popts ): array {
41        return $this->transformBodyOnly ?
42            [ ContentHolder::BODY_FRAGMENT ] :
43            $po->getContentHolder()->getFragmentNames();
44    }
45
46    /**
47     * @inheritDoc
48     */
49    public function transform(
50        ParserOutput $po, ParserOptions $popts, array &$options
51    ): ParserOutput {
52        foreach ( $this->getFragmentsToTransform( $po, $popts ) as $key ) {
53            $dom = $po->getContentHolder()->getAsDom( $key );
54            if ( $dom ) {
55                $dom = $this->transformDOM( $dom, $po, $popts, $options );
56                $po->getContentHolder()->setAsDom( $key, $dom );
57            }
58        }
59        return $po;
60    }
61
62    /** Applies the transformation to a DOM document */
63    abstract public function transformDOM(
64        DocumentFragment $df, ParserOutput $po, ParserOptions $popts, array &$options
65    ): DocumentFragment;
66
67    /**
68     * Helper method for DOM transforms to easily create DOM Elements with
69     * the given attributes and children.
70     *
71     * @param Document $doc Document holding the new element
72     * @param string $name Lowercase tag name of the new element
73     * @param array<string,string> $attribs Associative array between the
74     *   name and (unescaped) value of the attributes of the new element
75     * @param Node|string ...$children List of child nodes for the new element.
76     *   Unescaped strings are converted to new Text Nodes before their
77     *   insertion in the tree.
78     * @return Element
79     * @throws \DOMException
80     */
81    public function createElement(
82        Document $doc, string $name, array $attribs = [], Node|string ...$children
83    ): Element {
84        $el = $doc->createElement( $name );
85        foreach ( $attribs as $key => $value ) {
86            $el->setAttribute( $key, $value );
87        }
88        DOMCompat::append( $el, ...$children );
89        return $el;
90    }
91}