Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
70.59% covered (warning)
70.59%
48 / 68
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
CargoFeedFormat
70.59% covered (warning)
70.59%
48 / 68
0.00% covered (danger)
0.00%
0 / 4
26.24
0.00% covered (danger)
0.00%
0 / 1
 allowedParameters
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 queryAndDisplay
76.92% covered (warning)
76.92%
10 / 13
0.00% covered (danger)
0.00%
0 / 1
7.60
 getFeedType
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 outputFeed
88.37% covered (warning)
88.37%
38 / 43
0.00% covered (danger)
0.00%
0 / 1
8.10
1<?php
2/**
3 * @ingroup Cargo
4 * @file
5 */
6
7use MediaWiki\MediaWikiServices;
8
9/**
10 * Handle the feed export format.
11 * @since 3.5
12 */
13class CargoFeedFormat extends CargoDeferredFormat {
14
15    public static function allowedParameters() {
16        return [
17            'feed type' => [ 'values' => [ 'atom', 'rss' ] ],
18            'link text' => [ 'type' => 'string' ],
19            'feed title' => [ 'type' => 'string' ],
20            'feed description' => [ 'type' => 'string' ],
21        ];
22    }
23
24    /**
25     * @param CargoSQLQuery[] $sqlQueries
26     * @param string[] $displayParams Unused
27     * @param string[]|null $querySpecificParams Unused
28     * @return string An HTML link to Special:CargoExport with the required query string.
29     */
30    public function queryAndDisplay( $sqlQueries, $displayParams, $querySpecificParams = null ) {
31        $queryParams = $this->sqlQueriesToQueryParams( $sqlQueries );
32        $queryParams['format'] = 'feed';
33
34        // Feed type. Defaults to the first one set in $wgAdvertisedFeedTypes.
35        $queryParams['feed type'] = $this->getFeedType( $displayParams['feed type'] ?? null );
36
37        // Feed title.
38        if ( isset( $displayParams['feed title'] ) && trim( $displayParams['feed title'] ) != '' ) {
39            $queryParams['feed title'] = $displayParams['feed title'];
40        }
41
42        // Feed description.
43        if ( isset( $displayParams['feed description'] ) && trim( $displayParams['feed description'] ) !== '' ) {
44            $queryParams['feed description'] = $displayParams['feed description'];
45        }
46
47        // Link.
48        if ( isset( $displayParams['link text'] ) && $displayParams['link text'] ) {
49            $linkText = $displayParams['link text'];
50        } else {
51            // The following messages can be used here:
52            // * feed-rss
53            // * feed-atom
54            $feedName = wfMessage( 'feed-' . $queryParams['feed type'] );
55            $linkText = wfMessage( 'cargo-viewfeed', [ $feedName ] )->parse();
56        }
57
58        // Output full anchor element. The array_filter is to avoid empty params.
59        $export = SpecialPage::getTitleFor( 'CargoExport' );
60        return Html::rawElement( 'a', [ 'href' => $export->getFullURL( array_filter( $queryParams ) ) ], $linkText );
61    }
62
63    /**
64     * Determine the feed type (Atom or RSS).
65     * @param string|null $in The user-provided value.
66     * @return string Either 'atom' or 'rss'.
67     */
68    private function getFeedType( string $in = null ): string {
69        $config = MediaWikiServices::getInstance()->getMainConfig();
70        $types = array_keys( $config->get( 'FeedClasses' ) );
71
72        // User-provided (if it's valid).
73        $inType = strtolower( trim( $in ?? '' ) );
74        if ( in_array( $inType, $types ) ) {
75            return $inType;
76        }
77
78        // Otherwise, fall back to Atom.
79        return 'atom';
80    }
81
82    /**
83     * Get the iCalendar format output.
84     * @param WebRequest $request
85     * @param CargoSQLQuery[] $sqlQueries
86     * @return string
87     */
88    public function outputFeed( WebRequest $request, $sqlQueries ) {
89        $queryParams = $this->sqlQueriesToQueryParams( $sqlQueries );
90        $queryParams['format'] = 'feed';
91        $feedType = $this->getFeedType( $request->getText( 'feed_type' ) );
92        $title = $request->getText( 'feed_title', 'News feed' );
93        $description = $request->getText( 'feed_description', '' );
94
95        $feedClasses = MediaWikiServices::getInstance()->getMainConfig()->get( 'FeedClasses' );
96        /** @var RSSFeed|AtomFeed $feed */
97        $feed = new $feedClasses[$feedType]( $title, $description, $request->getFullRequestURL() );
98
99        $parser = MediaWikiServices::getInstance()->getParser();
100        $pageTitle = $parser->getTitle();
101        $parserOptions = ParserOptions::newFromAnon();
102        $items = [];
103        foreach ( $sqlQueries as $sqlQuery ) {
104            $dateFields = $sqlQuery->getMainStartAndEndDateFields();
105
106            $queryResults = $sqlQuery->run();
107            foreach ( $queryResults as $queryResult ) {
108                $title = Title::newFromText( $queryResult['_pageName'] );
109                if ( isset( $queryResult['description'] ) ) {
110                    $description = $queryResult['description'];
111                    $parserOutput = $parser->parse( $description, $pageTitle, $parserOptions );
112                    $description = $parserOutput->getText();
113                } else {
114                    $wikiPage = new WikiPage( $title );
115                    if ( method_exists( MediaWikiServices::class, 'getContentRenderer' ) ) {
116                        // @todo Remove after dropping support for MediaWiki < 1.38.
117                        $description = MediaWikiServices::getInstance()
118                            ->getContentRenderer()
119                            ->getParserOutput( $wikiPage->getContent(), $title )
120                            ->getText();
121                    } else {
122                        $description = $wikiPage->getContent()->getParserOutput( $title )->getText();
123                    }
124                }
125                $item = new FeedItem(
126                    $queryResult['_pageName'] ?? '',
127                    $description,
128                    $queryResult['url'] ?? $title->getCanonicalURL(),
129                    $queryResult[$dateFields[0]] ?? '',
130                    $queryResult['author'] ?? '',
131                    $queryResult['comments'] ?? ''
132                );
133                if ( isset( $queryResult['id'] ) && !empty( $queryResult['id'] ) ) {
134                    $item->setUniqueId( $queryResult['id'] );
135                } else {
136                    $item->setUniqueId( $title->getCanonicalURL(), true );
137                }
138                $items[$queryResult[$dateFields[0]]] = $item;
139            }
140        }
141
142        // Output feed content.
143        $feed->outHeader();
144        foreach ( $items as $item ) {
145            $feed->outItem( $item );
146        }
147        $feed->outFooter();
148    }
149}