Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialFeedItem
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 4
156
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
72
 parseTimestamp
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 displayItem
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Extension\FeaturedFeeds;
4
5use MediaWiki\SpecialPage\UnlistedSpecialPage;
6use MediaWiki\Utils\MWTimestamp;
7use Wikimedia\ObjectCache\WANObjectCache;
8
9class SpecialFeedItem extends UnlistedSpecialPage {
10
11    /** @var WANObjectCache */
12    private $wanObjectCache;
13
14    /**
15     * @param WANObjectCache $wanObjectCache
16     */
17    public function __construct(
18        WANObjectCache $wanObjectCache
19    ) {
20        parent::__construct( 'FeedItem' );
21        $this->wanObjectCache = $wanObjectCache;
22    }
23
24    /** @inheritDoc */
25    public function execute( $par = '' ) {
26        $this->setHeaders();
27        $out = $this->getOutput();
28        $parts = explode( '/', $par );
29        if ( count( $parts ) != 3 ) {
30            $out->showErrorPage( 'error', 'ffeed-no-feed' );
31            return;
32        }
33        [ $feedName, $date, $langCode ] = $parts;
34        $feeds = FeaturedFeeds::getFeeds( $langCode );
35        if ( !isset( $feeds[$feedName] ) ) {
36            $out->showErrorPage( 'error', 'ffeed-feed-not-found', [ $feedName ] );
37            return;
38        }
39        $feed = $feeds[$feedName];
40        $timestamp = $this->parseTimestamp( $date );
41        if ( !$timestamp ) {
42            $out->showErrorPage( 'error', 'ffeed-invalid-timestamp' );
43            return;
44        }
45        $date = FeaturedFeeds::startOfDay( $timestamp );
46        // First, search in the general cache
47        foreach ( $feed->getFeedItems() as $item ) {
48            if ( $item->getRawDate() == $date ) {
49                $this->displayItem( $item );
50                return;
51            }
52        }
53
54        $cache = $this->wanObjectCache;
55
56        $item = $cache->getWithSetCallback(
57            $cache->makeKey(
58                'featured-feed',
59                $feedName,
60                $date,
61                $feed->getLanguage()->getCode()
62            ),
63            $cache::TTL_DAY,
64            static function () use ( $feed, $date ) {
65                $item = $feed->getFeedItem( $date );
66
67                if ( $item ) {
68                    return $item->toArray();
69                }
70
71                return false;
72            },
73            [ 'version' => FeaturedFeedChannel::VERSION ]
74        );
75
76        if ( $item ) {
77            $this->displayItem( FeaturedFeedItem::fromArray( $item ) );
78        } else {
79            $out->showErrorPage( 'error', 'ffeed-entry-not-found',
80                [ $this->getLanguage()->date( wfTimestamp( TS_UNIX, $date ), false, false ) ]
81            );
82        }
83    }
84
85    /**
86     * @param string $date
87     * @return string|false
88     */
89    private function parseTimestamp( $date ) {
90        if ( strlen( $date ) !== 14 ) {
91            return false;
92        }
93        return MWTimestamp::convert( TS_UNIX, $date );
94    }
95
96    private function displayItem( FeaturedFeedItem $item ) {
97        $out = $this->getOutput();
98        $out->setPageTitle( $item->getRawTitle() );
99        $out->addHTML( $item->getRawText() );
100    }
101}