Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
77.42% covered (warning)
77.42%
24 / 31
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
LabeledSectionContentFetcher
77.42% covered (warning)
77.42%
24 / 31
75.00% covered (warning)
75.00%
3 / 4
7.56
0.00% covered (danger)
0.00%
0 / 1
 getSections
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 getContent
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 getContentWithoutTags
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 getMatches
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\MassMessage\MessageContentFetcher;
5
6use MediaWiki\MassMessage\LanguageAwareText;
7use MediaWiki\Status\Status;
8
9/**
10 * Fetches content from labeled sections
11 * @author Abijeet Patro
12 * @since 2022.01
13 * @license GPL-2.0-or-later
14 */
15class LabeledSectionContentFetcher {
16    /**
17     * Returns labeled sections from the given page
18     *
19     * @param string $content
20     * @return string[]
21     */
22    public function getSections( string $content ): array {
23        preg_match_all(
24            '~<section[^>]+begin\s*=\s*([^ /]+)[^>]+>(.*?)<section[^>]+end\s*=\s*\\1~s',
25            $content,
26            $matches
27        );
28
29        return array_unique( $matches[1] );
30    }
31
32    /**
33     * Get content from a labeled section
34     *
35     * @param LanguageAwareText $content
36     * @param string $label
37     * @return Status
38     */
39    public function getContent( LanguageAwareText $content, string $label ): Status {
40        $matches = $this->getMatches( $content->getWikitext(), $label );
41
42        if ( $matches === null ) {
43            return Status::newFatal( 'massmessage-page-section-invalid' );
44        }
45
46        // Include section tags for backwards compatibility.
47        // https://phabricator.wikimedia.org/T254481#6865334
48        // In case there are multiple sections with same label, there will be multiple wrappers too.
49        // Because LabelsedSectionTransclusion supports that natively, I see no reason to try to
50        // simplify it to include only one wrapper.
51        $sectionContent = new LanguageAwareText(
52            trim( implode( "", $matches[0] ) ),
53            $content->getLanguageCode(),
54            $content->getLanguageDirection()
55        );
56
57        return Status::newGood( $sectionContent );
58    }
59
60    /**
61     * Get content from a labeled section without the section tags
62     *
63     * @param LanguageAwareText $content
64     * @param string $label
65     * @return Status
66     */
67    public function getContentWithoutTags( LanguageAwareText $content, string $label ): Status {
68        $matches = $this->getMatches( $content->getWikitext(), $label );
69
70        if ( $matches === null ) {
71            return Status::newFatal( 'massmessage-page-section-invalid' );
72        }
73
74        $sectionContent = new LanguageAwareText(
75            implode( "", $matches[1] ),
76            $content->getLanguageCode(),
77            $content->getLanguageDirection()
78        );
79
80        return Status::newGood( $sectionContent );
81    }
82
83    /**
84     * Find and return section contents with or without tags
85     *
86     * @param string $content
87     * @param string $label
88     * @return ?array
89     */
90    private function getMatches( string $content, string $label ): ?array {
91        $matches = [];
92        $label = preg_quote( $label, '~' );
93
94        // I looked into LabeledSectionTransclusion and it is not reusable here without a lot of
95        // rework -NL
96
97        $pattern = "~<section[^>]+begin\s*=\s*{$label}[^>]+>(.*?)<section[^>]+end\s*=\s*{$label}[^>]+>~s";
98        $ok = preg_match_all( $pattern, $content, $matches );
99
100        if ( $ok < 1 ) {
101            return null;
102        }
103
104        return $matches;
105    }
106}