Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 123 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
FeaturedFeedChannel | |
0.00% |
0 / 123 |
|
0.00% |
0 / 10 |
1122 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
fromArray | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
12 | |||
toArray | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
12 | |||
msg | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isOK | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getLanguage | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
init | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
30 | |||
getFeedItems | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
56 | |||
getFeedItem | |
0.00% |
0 / 32 |
|
0.00% |
0 / 1 |
42 | |||
getURL | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\FeaturedFeeds; |
4 | |
5 | use Language; |
6 | use MediaWiki\MediaWikiServices; |
7 | use MediaWiki\Revision\SlotRecord; |
8 | use MediaWiki\SpecialPage\SpecialPage; |
9 | use MediaWiki\Title\Title; |
10 | use MediaWiki\Utils\MWTimestamp; |
11 | use Message; |
12 | use Parser; |
13 | use ParserOptions; |
14 | use TextContent; |
15 | use UnexpectedValueException; |
16 | |
17 | class FeaturedFeedChannel { |
18 | /** |
19 | * Class version, increment it when changing class internals. |
20 | */ |
21 | public const VERSION = 2; |
22 | |
23 | /** |
24 | * @var Parser |
25 | */ |
26 | private static $parser; |
27 | private $languageCode; |
28 | |
29 | private $name; |
30 | private $options; |
31 | /** |
32 | * @var FeaturedFeedItem[]|false |
33 | */ |
34 | private $items = false; |
35 | private $page = false; |
36 | private $entryName = false; |
37 | private $titleForParse = false; |
38 | |
39 | public $title = false; |
40 | public $shortTitle = false; |
41 | public $description = false; |
42 | |
43 | /** |
44 | * @param string $name |
45 | * @param array $options |
46 | * @param string $languageCode |
47 | */ |
48 | public function __construct( $name, $options, $languageCode ) { |
49 | if ( !self::$parser ) { |
50 | self::$parser = MediaWikiServices::getInstance()->getParserFactory()->create(); |
51 | } |
52 | |
53 | $this->name = $name; |
54 | $this->options = $options; |
55 | if ( $options['inUserLanguage'] ) { |
56 | $this->languageCode = $languageCode; |
57 | } else { |
58 | $contLang = MediaWikiServices::getInstance()->getContentLanguage(); |
59 | $this->languageCode = $contLang->getCode(); |
60 | } |
61 | } |
62 | |
63 | public static function fromArray( array $array ) { |
64 | $channel = new FeaturedFeedChannel( |
65 | $array['name'], |
66 | $array['options'], |
67 | $array['lang'] |
68 | ); |
69 | |
70 | if ( $array['items'] !== false ) { |
71 | $channel->items = []; |
72 | foreach ( $array['items'] as $item ) { |
73 | $channel->items[] = FeaturedFeedItem::fromArray( $item ); |
74 | } |
75 | } |
76 | |
77 | $channel->page = $array['page']; |
78 | $channel->entryName = $array['entryName']; |
79 | $channel->titleForParse = $array['titleForParse']; |
80 | $channel->title = $array['title']; |
81 | $channel->shortTitle = $array['shortTitle']; |
82 | $channel->description = $array['description']; |
83 | |
84 | return $channel; |
85 | } |
86 | |
87 | public function toArray(): array { |
88 | $items = false; |
89 | if ( $this->items !== false ) { |
90 | $items = []; |
91 | |
92 | foreach ( $this->items as $item ) { |
93 | $items[] = $item->toArray(); |
94 | } |
95 | } |
96 | |
97 | return [ |
98 | 'name' => $this->name, |
99 | 'options' => $this->options, |
100 | 'lang' => $this->languageCode, |
101 | 'items' => $items, |
102 | 'page' => $this->page, |
103 | 'entryName' => $this->entryName, |
104 | 'titleForParse' => $this->titleForParse, |
105 | 'title' => $this->title, |
106 | 'shortTitle' => $this->shortTitle, |
107 | 'description' => $this->description, |
108 | ]; |
109 | } |
110 | |
111 | /** |
112 | * @param string $key |
113 | * @return Message |
114 | */ |
115 | private function msg( $key ) { |
116 | return wfMessage( $key )->inLanguage( $this->languageCode ); |
117 | } |
118 | |
119 | /** |
120 | * @return bool |
121 | */ |
122 | public function isOK() { |
123 | $this->init(); |
124 | return $this->page !== false; |
125 | } |
126 | |
127 | /** |
128 | * Returns language used by the feed |
129 | * @return Language |
130 | */ |
131 | public function getLanguage() { |
132 | return MediaWikiServices::getInstance()->getLanguageFactory() |
133 | ->getLanguage( $this->languageCode ); |
134 | } |
135 | |
136 | public function init() { |
137 | global $wgLanguageCode; |
138 | if ( $this->title !== false ) { |
139 | return; |
140 | } |
141 | $this->title = $this->msg( $this->options['title'] )->text(); |
142 | $this->shortTitle = $this->msg( $this->options['short-title'] )->text(); |
143 | $this->description = $this->msg( $this->options['description'] )->text(); |
144 | $pageMsg = $this->msg( $this->options['page'] )->params( $this->languageCode ); |
145 | if ( $pageMsg->isDisabled() ) { |
146 | // fall back manually, messages can be existent but empty |
147 | if ( $this->languageCode != $wgLanguageCode ) { |
148 | $pageMsg = wfMessage( $this->options['page'] ) |
149 | ->params( $this->languageCode ) |
150 | ->inContentLanguage(); |
151 | } |
152 | } |
153 | if ( $pageMsg->isDisabled() ) { |
154 | return; |
155 | } |
156 | $this->page = $pageMsg->plain(); |
157 | $this->page = str_replace( '$LANGUAGE', $this->languageCode, $this->page ); |
158 | $this->entryName = $this->msg( $this->options['entryName'] )->plain(); |
159 | } |
160 | |
161 | /** |
162 | * @return FeaturedFeedItem[] |
163 | */ |
164 | public function getFeedItems() { |
165 | $this->init(); |
166 | if ( $this->items === false ) { |
167 | $this->items = []; |
168 | switch ( $this->options['frequency'] ) { |
169 | case 'daily': |
170 | $ratio = 1; |
171 | $baseTime = FeaturedFeeds::todaysStart(); |
172 | break; |
173 | case 'weekly': |
174 | $ratio = 7; |
175 | $baseTime = FeaturedFeeds::startOfThisWeek(); |
176 | break; |
177 | default: |
178 | throw new UnexpectedValueException( "'{$this->options['frequency']}' is not a valid frequency" ); |
179 | } |
180 | for ( $i = 1 - $this->options['limit']; $i <= 0; $i++ ) { |
181 | $timestamp = $baseTime + $i * $ratio * 24 * 3600; |
182 | $item = $this->getFeedItem( $timestamp ); |
183 | if ( $item ) { |
184 | $this->items[] = $item; |
185 | } |
186 | } |
187 | } |
188 | return $this->items; |
189 | } |
190 | |
191 | /** |
192 | * |
193 | * @param int $date |
194 | * @return FeaturedFeedItem|false |
195 | */ |
196 | public function getFeedItem( $date ) { |
197 | $ts = new MWTimestamp( $date ); |
198 | $timestamp = $ts->getTimestamp( TS_MW ); |
199 | $parserOptions = ParserOptions::newFromAnon(); |
200 | $parserOptions->setTimestamp( $timestamp ); |
201 | $parserOptions->setUserLang( $this->getLanguage() ); |
202 | |
203 | if ( $this->titleForParse === false ) { |
204 | // parsing with such title makes stuff like {{CURRENTMONTH}} localised |
205 | $this->titleForParse = Title::newFromText( 'MediaWiki:Dummy/' . $this->languageCode ); |
206 | } |
207 | |
208 | $titleText = self::$parser->transformMsg( |
209 | $this->page, $parserOptions, $this->titleForParse ); |
210 | $title = Title::newFromText( $titleText ); |
211 | if ( !$title ) { |
212 | return false; |
213 | } |
214 | $rev = MediaWikiServices::getInstance()->getRevisionLookup() |
215 | ->getRevisionByTitle( $title ); |
216 | if ( !$rev ) { |
217 | // Page does not exist |
218 | return false; |
219 | } |
220 | |
221 | $content = $rev->getContent( SlotRecord::MAIN ); |
222 | $text = ( $content instanceof TextContent ) ? $content->getText() : null; |
223 | |
224 | if ( !$text ) { |
225 | return false; |
226 | } |
227 | $text = self::$parser->parse( $text, $title, $parserOptions )->getText( [ |
228 | 'enableSectionEditLinks' => false, |
229 | ] ); |
230 | $url = SpecialPage::getTitleFor( 'FeedItem', |
231 | $this->name . '/' . $timestamp . '/' . $this->languageCode |
232 | )->getFullURL(); |
233 | |
234 | return new FeaturedFeedItem( |
235 | self::$parser->transformMsg( $this->entryName, $parserOptions, $this->titleForParse ), |
236 | wfExpandUrl( $url ), |
237 | $text, |
238 | $timestamp |
239 | ); |
240 | } |
241 | |
242 | /** |
243 | * Returns a URL to the feed |
244 | * |
245 | * @param string $format Feed format, 'rss' or 'atom' |
246 | * @return string |
247 | */ |
248 | public function getURL( $format ) { |
249 | $contLang = MediaWikiServices::getInstance()->getContentLanguage(); |
250 | |
251 | $options = [ |
252 | 'action' => 'featuredfeed', |
253 | 'feed' => $this->name, |
254 | 'feedformat' => $format, |
255 | ]; |
256 | if ( $this->options['inUserLanguage'] && $this->languageCode != $contLang->getCode() ) { |
257 | $options['language'] = $this->languageCode; |
258 | } |
259 | return wfScript( 'api' ) . '?' . wfArrayToCgi( $options ); |
260 | } |
261 | } |