r108524 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r108523‎ | r108524 | r108525 >
Date:17:55, 10 January 2012
Author:maxsem
Status:resolved
Tags:
Comment:
Serious rewrite: to guarantee unique URLs (and therefore unique feed item IDs), introduced a new special page to view items
Modified paths:
  • /trunk/extensions/FeaturedFeeds/ApiFeaturedFeeds.php (modified) (history)
  • /trunk/extensions/FeaturedFeeds/FeaturedFeeds.alias.php (added) (history)
  • /trunk/extensions/FeaturedFeeds/FeaturedFeeds.body.php (modified) (history)
  • /trunk/extensions/FeaturedFeeds/FeaturedFeeds.i18n.php (modified) (history)
  • /trunk/extensions/FeaturedFeeds/FeaturedFeeds.php (modified) (history)
  • /trunk/extensions/FeaturedFeeds/SpecialFeedItem.php (added) (history)

Diff [purge]

Index: trunk/extensions/FeaturedFeeds/FeaturedFeeds.alias.php
@@ -0,0 +1,14 @@
 2+<?php
 3+/**
 4+ * Aliases for Special:FeedItem
 5+ *
 6+ * @file
 7+ * @ingroup Extensions
 8+ */
 9+
 10+$specialPageAliases = array();
 11+
 12+/** English (English) */
 13+$specialPageAliases['en'] = array(
 14+ 'FeedItem' => array( 'FeedItem' ),
 15+);
Index: trunk/extensions/FeaturedFeeds/ApiFeaturedFeeds.php
@@ -35,12 +35,12 @@
3636 $ourFeed = $feeds[$params['feed']];
3737
3838 $feedClass = new $wgFeedClasses[$params['feedformat']] (
39 - $ourFeed['title'],
40 - $ourFeed['description'],
41 - FeaturedFeeds::getFeedURL( $ourFeed, $params['feedformat'] )
 39+ $ourFeed->title,
 40+ $ourFeed->description,
 41+ $ourFeed->getURL( $params['feedformat'] )
4242 );
4343
44 - ApiFormatFeedWrapper::setResult( $this->getResult(), $feedClass, $ourFeed['entries'] );
 44+ ApiFormatFeedWrapper::setResult( $this->getResult(), $feedClass, $ourFeed->getFeedItems() );
4545
4646 // Cache stuff in squids
4747 $this->getMain()->setCacheMode( 'public' );
@@ -99,7 +99,7 @@
100100
101101 if ( version_compare( $wgVersion, '1.19alpha', '>=' ) ) {
102102 return array(
103 - "api.php?action=featuredfeed&feed=$feed" => "Retrieve feed `$feed'",
 103+ "api.php?action=featuredfeed&feed=$feed" => "Retrieve feed ``$feed'",
104104 );
105105 } else {
106106 return array(
Index: trunk/extensions/FeaturedFeeds/FeaturedFeeds.body.php
@@ -1,7 +1,6 @@
22 <?php
33
44 class FeaturedFeeds {
5 -
65 /**
76 * Returns the list of feeds
87 *
@@ -44,8 +43,8 @@
4544 $out->addLink( array(
4645 'rel' => 'alternate',
4746 'type' => "application/$type+xml",
48 - 'title' => $feed['title'],
49 - 'href' => self::getFeedURL( $feed, $type ),
 47+ 'title' => $feed->title,
 48+ 'href' => $feed->getURL( $type ),
5049 ) );
5150 }
5251 }
@@ -75,53 +74,14 @@
7675 }
7776
7877 $feeds = array();
79 - $parserOptions = new ParserOptions();
80 -
8178 $requestedLang = Language::factory( $langCode );
8279 $parser = new Parser();
8380 foreach ( $feedDefs as $name => $opts ) {
84 - $feed = array( 'name' => $name );
85 -
86 - $feed['inUserLanguage'] = $opts['inUserLanguage'];
87 - $lang = $opts['inUserLanguage'] ? $requestedLang : $wgContLang;
88 - $feed['language'] = $lang->getCode();
89 - $pageMsg = wfMessage( $opts['page'] )->inLanguage( $lang );
90 - if ( $pageMsg->isDisabled() ) {
 81+ $feed = new FeaturedFeedChannel( $name, $opts, $requestedLang );
 82+ if ( !$feed->isOK() ) {
9183 continue;
9284 }
93 - $page = $pageMsg->plain();
94 - $feed['title'] = wfMessage( $opts['title'] )->inLanguage( $lang )->text();
95 - $feed['description'] = wfMessage( $opts['description'] )->inLanguage( $lang )->text();
96 - $entryName = wfMessage( $opts['entryName'] )->inLanguage( $lang )->plain();
97 - $feed['entries'] = array();
98 -
99 - $parserOptions->setUserLang( $lang );
100 - for ( $i = 1 - $opts['limit']; $i <= 0; $i++ ) {
101 - $time = self::todaysStart() + $i * 24 * 3600;
102 - $parserOptions->setTimestamp( $time );
103 -
104 - $titleText = $parser->transformMsg( $page, $parserOptions );
105 - $title = Title::newFromText( $titleText );
106 - if ( !$title ) {
107 - throw new MWException( "Invalid page name $titleText" );
108 - }
109 - $rev = Revision::newFromTitle( $title );
110 - if ( !$rev ) {
111 - continue; // page does not exist
112 - }
113 - $text = $rev->getText();
114 - if ( !$text ) {
115 - continue;
116 - }
117 - $text = $parser->parse( $text, $title, $parserOptions )->getText();
118 - $feed['entries'][] = new FeedItem(
119 - $parser->transformMsg( $entryName, $parserOptions ),
120 - $text,
121 - wfExpandUrl( $title->getFullURL() ),
122 - $time
123 - );
124 - }
125 -
 85+ $feed->getFeedItems();
12686 $feeds[$name] = $feed;
12787 }
12888 wfProfileOut( __METHOD__ );
@@ -129,6 +89,8 @@
13090 return $feeds;
13191 }
13292
 93+
 94+
13395 /**
13496 * Returns the Unix timestamp of current day's first second
13597 *
@@ -137,48 +99,201 @@
138100 public static function todaysStart() {
139101 static $time = false;
140102 if ( !$time ) {
141 - global $wgLocaltimezone;
142 - if ( isset( $wgLocaltimezone ) ) {
143 - $tz = new DateTimeZone( $wgLocaltimezone );
144 - } else {
145 - $tz = new DateTimeZone( date_default_timezone_get() );
146 - }
147 - $dt = new DateTime( 'now', $tz );
148 - $dt->setTime( 0, 0, 0 );
149 - $time = $dt->getTimestamp();
 103+ $time = self::startOfDay( time() );
150104 }
151105 return $time;
152106 }
153107
154108 /**
 109+ * Returns the Unix timestamp of current day's first second
 110+ *
 111+ * @return int Timestamp
 112+ */
 113+ public static function startOfDay( $timestamp ) {
 114+ global $wgLocaltimezone;
 115+ if ( isset( $wgLocaltimezone ) ) {
 116+ $tz = new DateTimeZone( $wgLocaltimezone );
 117+ } else {
 118+ $tz = new DateTimeZone( date_default_timezone_get() );
 119+ }
 120+ $dt = new DateTime( "@$timestamp", $tz );
 121+ $dt->setTime( 0, 0, 0 );
 122+ return $dt->getTimestamp();
 123+ }
 124+
 125+ /**
 126+ * Returns the number of seconds a feed should stay in cache
 127+ *
 128+ * @return int: Time in seconds
 129+ */
 130+ public static function getMaxAge() {
 131+ // add 10 seconds to cater for time deviation between servers
 132+ $expiry = self::todaysStart() + 24 * 3600 - wfTimestamp() + 10;
 133+ return min( $expiry, 3600 );
 134+ }
 135+}
 136+
 137+class FeaturedFeedChannel {
 138+ /**
 139+ * @var ParserOptions
 140+ */
 141+ private static $parserOptions = null;
 142+ /**
 143+ * @var Parser
 144+ */
 145+ private static $parser;
 146+
 147+ /**
 148+ * @var Language
 149+ */
 150+ private $language;
 151+
 152+ private $name;
 153+ private $options;
 154+ private $items = false;
 155+ private $page = false;
 156+ private $entryName;
 157+
 158+ public $title = false;
 159+ public $description;
 160+
 161+ public function __construct( $name, $options, $lang ) {
 162+ global $wgContLang;
 163+ if ( !self::$parserOptions ) {
 164+ self::$parserOptions = new ParserOptions();
 165+ self::$parser = new Parser();
 166+ }
 167+ $this->name = $name;
 168+ $this->options = $options;
 169+ if ( $options['inUserLanguage'] ) {
 170+ $this->language = $lang;
 171+ } else {
 172+ $this->language = $wgContLang;
 173+ }
 174+ }
 175+
 176+ private function msg( $key ) {
 177+ return wfMessage( $key )->inLanguage( $this->language );
 178+ }
 179+
 180+ public function isOK() {
 181+ $this->init();
 182+ return $this->page !== false;
 183+ }
 184+
 185+ /**
 186+ * Returns language used by the feed
 187+ * @return Language
 188+ */
 189+ public function getLanguage() {
 190+ return $this->language;
 191+ }
 192+
 193+ public function init() {
 194+ if ( $this->title !== false ) {
 195+ return;
 196+ }
 197+ $this->title = $this->msg( $this->options['title'] )->text();
 198+ $this->description = $this->msg( $this->options['description'] )->text();
 199+ $pageMsg = $this->msg( $this->options['page'] );
 200+ if ( $pageMsg->isDisabled() ) {
 201+ return;
 202+ }
 203+ $this->page = $pageMsg->plain();
 204+ $this->entryName = $this->msg( $this->options['entryName'] )->plain();
 205+ }
 206+
 207+ public function getFeedItems() {
 208+ $this->init();
 209+ if ( $this->items === false ) {
 210+ $this->items = array();
 211+ for ( $i = 1 - $this->options['limit']; $i <= 0; $i++ ) {
 212+ $timestamp = FeaturedFeeds::todaysStart() + $i * 24 * 3600;
 213+ $item = $this->getFeedItem( $timestamp );
 214+ if ( $item ) {
 215+ $this->items[] = $item;
 216+ }
 217+ }
 218+ }
 219+ return $this->items;
 220+ }
 221+
 222+ /**
 223+ *
 224+ * @param int $date
 225+ * @return FeaturedFeedItem
 226+ */
 227+ public function getFeedItem( $date ) {
 228+ self::$parserOptions->setTimestamp( $date );
 229+ self::$parserOptions->setUserLang( $this->language );
 230+
 231+ $titleText = self::$parser->transformMsg( $this->page, self::$parserOptions );
 232+ $title = Title::newFromText( $titleText );
 233+ if ( !$title ) {
 234+ return false;
 235+ }
 236+ $rev = Revision::newFromTitle( $title );
 237+ if ( !$rev ) {
 238+ return false; // page does not exist
 239+ }
 240+ $text = $rev->getText();
 241+ if ( !$text ) {
 242+ return false;
 243+ }
 244+ $text = self::$parser->parse( $text, $title, self::$parserOptions )->getText();
 245+ $url = SpecialPage::getTitleFor( 'FeedItem' ,
 246+ $this->name . '/' . wfTimestamp( TS_MW, $date ) . '/' . $this->language->getCode()
 247+ )->getFullURL();
 248+
 249+ return new FeaturedFeedItem(
 250+ self::$parser->transformMsg( $this->entryName, self::$parserOptions ),
 251+ wfExpandUrl( $url ),
 252+ $text,
 253+ $date
 254+ );
 255+ }
 256+
 257+ /**
155258 * Returns a URL to the feed
156259 *
157 - * @param Array $feed: Feed description returned by getFeeds()
158260 * @param type $format: Feed format, 'rss' or 'atom'
159261 * @return String
160262 */
161 - public static function getFeedURL( $feed, $format ) {
 263+ public function getURL( $format ) {
162264 global $wgContLang;
163265
164266 $options = array(
165267 'action' => 'featuredfeed',
166 - 'feed' => $feed['name'],
 268+ 'feed' => $this->name,
167269 'feedformat' => $format,
168270 );
169 - if ( $feed['inUserLanguage'] && $feed['language'] != $wgContLang->getCode() ) {
170 - $options['language'] = $feed['language'];
 271+ if ( $this->options['inUserLanguage'] && $this->language->getCode() != $wgContLang->getCode() ) {
 272+ $options['language'] = $this->language->getCode();
171273 }
172274 return wfScript( 'api' ) . '?' . wfArrayToCGI( $options );
173275 }
 276+}
174277
175 - /**
176 - * Returns the number of seconds a feed should stay in cache
177 - *
178 - * @return int: Time in seconds
179 - */
180 - public static function getMaxAge() {
181 - // add 10 seconds to cater for time deviation between servers
182 - $expiry = self::todaysStart() + 24 * 3600 - wfTimestamp() + 10;
183 - return min( $expiry, 3600 );
 278+class FeaturedFeedItem extends FeedItem {
 279+ const CACHE_VERSION = 1;
 280+
 281+ public function __construct( $title, $url, $text, $date ) {
 282+ parent::__construct( $title, $text, $url, $date );
184283 }
 284+
 285+ public function getRawDate() {
 286+ return $this->date;
 287+ }
 288+
 289+ public function getRawTitle() {
 290+ return $this->title;
 291+ }
 292+
 293+ public function getRawUrl() {
 294+ return $this->url;
 295+ }
 296+
 297+ public function getRawText() {
 298+ return $this->description;
 299+ }
185300 }
Index: trunk/extensions/FeaturedFeeds/SpecialFeedItem.php
@@ -0,0 +1,57 @@
 2+<?php
 3+
 4+class SpecialFeedItem extends UnlistedSpecialPage {
 5+ public function __construct() {
 6+ parent::__construct( 'FeedItem' );
 7+ }
 8+
 9+ public function execute( $par = '' ) {
 10+ global $wgMemc;
 11+ $this->setHeaders();
 12+ $out = $this->getOutput();
 13+ $parts = explode( '/', $par );
 14+ if ( count( $parts ) != 3 ) {
 15+ $out->showErrorPage( 'error', 'ffeed-no-feed' );
 16+ return;
 17+ }
 18+ list( $feedName, $date, $langCode ) = $parts;
 19+ $feeds = FeaturedFeeds::getFeeds( $langCode );
 20+ if ( !isset( $feeds[$feedName] ) ) {
 21+ $out->showErrorPage( 'error', 'ffeed-feed-not-found', array( $feedName ) );
 22+ return;
 23+ }
 24+ $feed = $feeds[$feedName];
 25+ $date = FeaturedFeeds::startOfDay( wfTimestamp( TS_UNIX, $date ) );
 26+ // First, search in the general cache
 27+ foreach ( $feed->getFeedItems() as $item ) {
 28+ if ( $item->getRawDate() == $date ) {
 29+ $this->displayItem( $item );
 30+ return;
 31+ }
 32+ }
 33+ $key = wfMemcKey( 'featured', $feedName, $date, $feed->getLanguage()->getCode(),
 34+ FeaturedFeedItem::CACHE_VERSION
 35+ );
 36+ $item = $wgMemc->get( $key );
 37+ if ( !$item ) {
 38+ $item = $feed->getFeedItem( $date );
 39+ if ( $item ) {
 40+ $wgMemc->set( $key, $item, 3600 * 24 );
 41+ }
 42+ }
 43+ if ( $item ) {
 44+ $this->displayItem( $item );
 45+ } else {
 46+ var_dump($this->getUser()->getDatePreference());
 47+ $out->showErrorPage( 'error', 'ffeed-entry-not-found',
 48+ array( $this->getLanguage()->sprintfDate( $this->getUser()->getDatePreference(), $date ) )
 49+ );
 50+ }
 51+ }
 52+
 53+ private function displayItem( FeaturedFeedItem $item ) {
 54+ $out = $this->getOutput();
 55+ $out->setPageTitle( $item->getRawTitle() );
 56+ $out->addHTML( $item->getRawText() );
 57+ }
 58+}
Property changes on: trunk/extensions/FeaturedFeeds/SpecialFeedItem.php
___________________________________________________________________
Added: svn:eol-style
159 + native
Index: trunk/extensions/FeaturedFeeds/FeaturedFeeds.i18n.php
@@ -13,6 +13,9 @@
1414 */
1515 $messages['en'] = array(
1616 'ffeed-desc' => "Adds syndication feeds of wiki's featured content",
 17+ 'ffeed-no-feed' => 'Feed not specified',
 18+ 'ffeed-feed-not-found' => 'Feed $1 not found',
 19+ 'ffeed-entry-not-found' => 'Feed entry for $1 not found',
1720
1821 # Featured Article
1922 'ffeed-fa-page' => '', # do not localise
@@ -56,6 +59,8 @@
5760 */
5861 $messages['qqq'] = array(
5962 'ffeed-desc' => '{{desc}}',
 63+ 'ffeed-feed-not-found' => '$1 is feed name',
 64+ 'ffeed-entry-not-found' => '$1 is date',
6065 'ffeed-fa-title' => 'Title of the Featured Articles [[w:web feed|syndication feed]]',
6166 'ffeed-fa-desc' => 'Description of the Featured Articles [[w:web feed|syndication feed]]',
6267 'ffeed-fa-entry' => "Title of day's entry in the Featured Articles [[w:web feed|syndication feed]]",
Index: trunk/extensions/FeaturedFeeds/FeaturedFeeds.php
@@ -19,11 +19,17 @@
2020
2121 $dir = dirname( __FILE__ );
2222
 23+$wgAutoloadClasses['ApiFeaturedFeeds'] = "$dir/ApiFeaturedFeeds.php";
2324 $wgAutoloadClasses['FeaturedFeeds'] = "$dir/FeaturedFeeds.body.php";
24 -$wgAutoloadClasses['ApiFeaturedFeeds'] = "$dir/ApiFeaturedFeeds.php";
 25+$wgAutoloadClasses['FeaturedFeedChannel'] = "$dir/FeaturedFeeds.body.php";
 26+$wgAutoloadClasses['FeaturedFeedItem'] = "$dir/FeaturedFeeds.body.php";
 27+$wgAutoloadClasses['SpecialFeedItem'] = "$dir/SpecialFeedItem.php";
2528
2629 $wgExtensionMessagesFiles['FeaturedFeeds'] = "$dir/FeaturedFeeds.i18n.php";
 30+$wgExtensionMessagesFiles['FeaturedFeedsAliases'] = "$dir/FeaturedFeeds.alias.php";
2731
 32+$wgSpecialPages['FeedItem'] = 'SpecialFeedItem';
 33+
2834 $wgAPIModules['featuredfeed'] = 'ApiFeaturedFeeds';
2935
3036 $wgHooks['BeforePageDisplay'][] = 'FeaturedFeeds::beforePageDisplay';

Follow-up revisions

RevisionCommit summaryAuthorDate
r108526Follow-up r108524: rm var_dump()maxsem17:58, 10 January 2012
r108528Follow-up r108524: fixed date formattingmaxsem18:07, 10 January 2012
r108548r108524: Register new alias file for translatewiki.netraymond20:55, 10 January 2012

Status & tagging log