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 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    public function execute( $par = '' ) {
25        $this->setHeaders();
26        $out = $this->getOutput();
27        $parts = explode( '/', $par );
28        if ( count( $parts ) != 3 ) {
29            $out->showErrorPage( 'error', 'ffeed-no-feed' );
30            return;
31        }
32        [ $feedName, $date, $langCode ] = $parts;
33        $feeds = FeaturedFeeds::getFeeds( $langCode );
34        if ( !isset( $feeds[$feedName] ) ) {
35            $out->showErrorPage( 'error', 'ffeed-feed-not-found', [ $feedName ] );
36            return;
37        }
38        $feed = $feeds[$feedName];
39        $timestamp = $this->parseTimestamp( $date );
40        if ( !$timestamp ) {
41            $out->showErrorPage( 'error', 'ffeed-invalid-timestamp' );
42            return;
43        }
44        $date = FeaturedFeeds::startOfDay( $timestamp );
45        // First, search in the general cache
46        foreach ( $feed->getFeedItems() as $item ) {
47            if ( $item->getRawDate() == $date ) {
48                $this->displayItem( $item );
49                return;
50            }
51        }
52
53        $cache = $this->wanObjectCache;
54
55        $item = $cache->getWithSetCallback(
56            $cache->makeKey(
57                'featured-feed',
58                $feedName,
59                $date,
60                $feed->getLanguage()->getCode()
61            ),
62            $cache::TTL_DAY,
63            static function () use ( $feed, $date ) {
64                $item = $feed->getFeedItem( $date );
65
66                if ( $item ) {
67                    return $item->toArray();
68                }
69
70                return false;
71            },
72            [ 'version' => FeaturedFeedChannel::VERSION ]
73        );
74
75        if ( $item ) {
76            $this->displayItem( FeaturedFeedItem::fromArray( $item ) );
77        } else {
78            $out->showErrorPage( 'error', 'ffeed-entry-not-found',
79                [ $this->getLanguage()->date( wfTimestamp( TS_UNIX, $date ), false, false ) ]
80            );
81        }
82    }
83
84    private function parseTimestamp( $date ) {
85        if ( strlen( $date ) !== 14 ) {
86            return false;
87        }
88        return MWTimestamp::convert( TS_UNIX, $date );
89    }
90
91    private function displayItem( FeaturedFeedItem $item ) {
92        $out = $this->getOutput();
93        $out->setPageTitle( $item->getRawTitle() );
94        $out->addHTML( $item->getRawText() );
95    }
96}