From: withoutaname Date: Wed, 16 Jul 2014 00:30:46 +0000 (-0700) Subject: Move ChangesFeed to includes/changes/ folder X-Git-Tag: 1.31.0-rc.0~14931^2 X-Git-Url: http://git.cyclocoop.org/%40spipnet%40?a=commitdiff_plain;h=2be66e38e282a8605027753875c092c74fa90c1c;p=lhc%2Fweb%2Fwiklou.git Move ChangesFeed to includes/changes/ folder Change-Id: I4ec541e8fe4234970972904592af2e11375e974d --- diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index 8b4895a174..a58639dadc 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -42,7 +42,6 @@ $wgAutoloadLocalClasses = array( 'Category' => 'includes/Category.php', 'Categoryfinder' => 'includes/Categoryfinder.php', 'CategoryViewer' => 'includes/CategoryViewer.php', - 'ChangesFeed' => 'includes/ChangesFeed.php', 'ChangeTags' => 'includes/ChangeTags.php', 'ChannelFeed' => 'includes/Feed.php', 'Collation' => 'includes/Collation.php', @@ -360,6 +359,7 @@ $wgAutoloadLocalClasses = array( 'ResourceFileCache' => 'includes/cache/ResourceFileCache.php', # includes/changes + 'ChangesFeed' => 'includes/changes/ChangesFeed.php', 'ChangesList' => 'includes/changes/ChangesList.php', 'EnhancedChangesList' => 'includes/changes/EnhancedChangesList.php', 'OldChangesList' => 'includes/changes/OldChangesList.php', diff --git a/includes/ChangesFeed.php b/includes/ChangesFeed.php deleted file mode 100644 index fb491e50b3..0000000000 --- a/includes/ChangesFeed.php +++ /dev/null @@ -1,239 +0,0 @@ -format = $format; - $this->type = $type; - } - - /** - * Get a ChannelFeed subclass object to use - * - * @param string $title Feed's title - * @param string $description Feed's description - * @param string $url Url of origin page - * @return ChannelFeed|bool ChannelFeed subclass or false on failure - */ - public function getFeedObject( $title, $description, $url ) { - global $wgSitename, $wgLanguageCode, $wgFeedClasses; - - if ( !isset( $wgFeedClasses[$this->format] ) ) { - return false; - } - - if ( !array_key_exists( $this->format, $wgFeedClasses ) ) { - // falling back to atom - $this->format = 'atom'; - } - - $feedTitle = "$wgSitename - {$title} [$wgLanguageCode]"; - return new $wgFeedClasses[$this->format]( - $feedTitle, htmlspecialchars( $description ), $url ); - } - - /** - * Generates feed's content - * - * @param ChannelFeed $feed ChannelFeed subclass object (generally the one returned - * by getFeedObject()) - * @param ResultWrapper $rows ResultWrapper object with rows in recentchanges table - * @param int $lastmod Timestamp of the last item in the recentchanges table (only - * used for the cache key) - * @param FormOptions $opts As in SpecialRecentChanges::getDefaultOptions() - * @return null|bool True or null - */ - public function execute( $feed, $rows, $lastmod, $opts ) { - global $wgLang, $wgRenderHashAppend; - - if ( !FeedUtils::checkFeedOutput( $this->format ) ) { - return null; - } - - $optionsHash = md5( serialize( $opts->getAllValues() ) ) . $wgRenderHashAppend; - $timekey = wfMemcKey( $this->type, $this->format, $wgLang->getCode(), $optionsHash, 'timestamp' ); - $key = wfMemcKey( $this->type, $this->format, $wgLang->getCode(), $optionsHash ); - - FeedUtils::checkPurge( $timekey, $key ); - - /** - * Bumping around loading up diffs can be pretty slow, so where - * possible we want to cache the feed output so the next visitor - * gets it quick too. - */ - $cachedFeed = $this->loadFromCache( $lastmod, $timekey, $key ); - if ( is_string( $cachedFeed ) ) { - wfDebug( "RC: Outputting cached feed\n" ); - $feed->httpHeaders(); - echo $cachedFeed; - } else { - wfDebug( "RC: rendering new feed and caching it\n" ); - ob_start(); - self::generateFeed( $rows, $feed ); - $cachedFeed = ob_get_contents(); - ob_end_flush(); - $this->saveToCache( $cachedFeed, $timekey, $key ); - } - return true; - } - - /** - * Save to feed result to $messageMemc - * - * @param string $feed Feed's content - * @param string $timekey Memcached key of the last modification - * @param string $key Memcached key of the content - */ - public function saveToCache( $feed, $timekey, $key ) { - global $messageMemc; - $expire = 3600 * 24; # One day - $messageMemc->set( $key, $feed, $expire ); - $messageMemc->set( $timekey, wfTimestamp( TS_MW ), $expire ); - } - - /** - * Try to load the feed result from $messageMemc - * - * @param int $lastmod Timestamp of the last item in the recentchanges table - * @param string $timekey Memcached key of the last modification - * @param string $key Memcached key of the content - * @return string|bool Feed's content on cache hit or false on cache miss - */ - public function loadFromCache( $lastmod, $timekey, $key ) { - global $wgFeedCacheTimeout, $wgOut, $messageMemc; - - $feedLastmod = $messageMemc->get( $timekey ); - - if ( ( $wgFeedCacheTimeout > 0 ) && $feedLastmod ) { - /** - * If the cached feed was rendered very recently, we may - * go ahead and use it even if there have been edits made - * since it was rendered. This keeps a swarm of requests - * from being too bad on a super-frequently edited wiki. - */ - - $feedAge = time() - wfTimestamp( TS_UNIX, $feedLastmod ); - $feedLastmodUnix = wfTimestamp( TS_UNIX, $feedLastmod ); - $lastmodUnix = wfTimestamp( TS_UNIX, $lastmod ); - - if ( $feedAge < $wgFeedCacheTimeout || $feedLastmodUnix > $lastmodUnix ) { - wfDebug( "RC: loading feed from cache ($key; $feedLastmod; $lastmod)...\n" ); - if ( $feedLastmodUnix < $lastmodUnix ) { - $wgOut->setLastModified( $feedLastmod ); // bug 21916 - } - return $messageMemc->get( $key ); - } else { - wfDebug( "RC: cached feed timestamp check failed ($feedLastmod; $lastmod)\n" ); - } - } - return false; - } - - /** - * Generate the feed items given a row from the database, printing the feed. - * @param object $rows DatabaseBase resource with recentchanges rows - * @param Feed $feed - */ - public static function generateFeed( $rows, &$feed ) { - wfProfileIn( __METHOD__ ); - $items = self::buildItems( $rows ); - $feed->outHeader(); - foreach ( $items as $item ) { - $feed->outItem( $item ); - } - $feed->outFooter(); - wfProfileOut( __METHOD__ ); - } - - /** - * Generate the feed items given a row from the database. - * @param object $rows DatabaseBase resource with recentchanges rows - */ - public static function buildItems( $rows ) { - wfProfileIn( __METHOD__ ); - $items = array(); - - # Merge adjacent edits by one user - $sorted = array(); - $n = 0; - foreach ( $rows as $obj ) { - if ( $n > 0 && - $obj->rc_type == RC_EDIT && - $obj->rc_namespace >= 0 && - $obj->rc_cur_id == $sorted[$n - 1]->rc_cur_id && - $obj->rc_user_text == $sorted[$n - 1]->rc_user_text ) { - $sorted[$n - 1]->rc_last_oldid = $obj->rc_last_oldid; - } else { - $sorted[$n] = $obj; - $n++; - } - } - - foreach ( $sorted as $obj ) { - $title = Title::makeTitle( $obj->rc_namespace, $obj->rc_title ); - $talkpage = MWNamespace::canTalk( $obj->rc_namespace ) - ? $title->getTalkPage()->getFullURL() - : ''; - - // Skip items with deleted content (avoids partially complete/inconsistent output) - if ( $obj->rc_deleted ) { - continue; - } - - if ( $obj->rc_this_oldid ) { - $url = $title->getFullURL( array( - 'diff' => $obj->rc_this_oldid, - 'oldid' => $obj->rc_last_oldid, - ) ); - } else { - // log entry or something like that. - $url = $title->getFullURL(); - } - - $items[] = new FeedItem( - $title->getPrefixedText(), - FeedUtils::formatDiff( $obj ), - $url, - $obj->rc_timestamp, - ( $obj->rc_deleted & Revision::DELETED_USER ) - ? wfMessage( 'rev-deleted-user' )->escaped() : $obj->rc_user_text, - $talkpage - ); - } - - wfProfileOut( __METHOD__ ); - return $items; - } -} diff --git a/includes/changes/ChangesFeed.php b/includes/changes/ChangesFeed.php new file mode 100644 index 0000000000..fb491e50b3 --- /dev/null +++ b/includes/changes/ChangesFeed.php @@ -0,0 +1,239 @@ +format = $format; + $this->type = $type; + } + + /** + * Get a ChannelFeed subclass object to use + * + * @param string $title Feed's title + * @param string $description Feed's description + * @param string $url Url of origin page + * @return ChannelFeed|bool ChannelFeed subclass or false on failure + */ + public function getFeedObject( $title, $description, $url ) { + global $wgSitename, $wgLanguageCode, $wgFeedClasses; + + if ( !isset( $wgFeedClasses[$this->format] ) ) { + return false; + } + + if ( !array_key_exists( $this->format, $wgFeedClasses ) ) { + // falling back to atom + $this->format = 'atom'; + } + + $feedTitle = "$wgSitename - {$title} [$wgLanguageCode]"; + return new $wgFeedClasses[$this->format]( + $feedTitle, htmlspecialchars( $description ), $url ); + } + + /** + * Generates feed's content + * + * @param ChannelFeed $feed ChannelFeed subclass object (generally the one returned + * by getFeedObject()) + * @param ResultWrapper $rows ResultWrapper object with rows in recentchanges table + * @param int $lastmod Timestamp of the last item in the recentchanges table (only + * used for the cache key) + * @param FormOptions $opts As in SpecialRecentChanges::getDefaultOptions() + * @return null|bool True or null + */ + public function execute( $feed, $rows, $lastmod, $opts ) { + global $wgLang, $wgRenderHashAppend; + + if ( !FeedUtils::checkFeedOutput( $this->format ) ) { + return null; + } + + $optionsHash = md5( serialize( $opts->getAllValues() ) ) . $wgRenderHashAppend; + $timekey = wfMemcKey( $this->type, $this->format, $wgLang->getCode(), $optionsHash, 'timestamp' ); + $key = wfMemcKey( $this->type, $this->format, $wgLang->getCode(), $optionsHash ); + + FeedUtils::checkPurge( $timekey, $key ); + + /** + * Bumping around loading up diffs can be pretty slow, so where + * possible we want to cache the feed output so the next visitor + * gets it quick too. + */ + $cachedFeed = $this->loadFromCache( $lastmod, $timekey, $key ); + if ( is_string( $cachedFeed ) ) { + wfDebug( "RC: Outputting cached feed\n" ); + $feed->httpHeaders(); + echo $cachedFeed; + } else { + wfDebug( "RC: rendering new feed and caching it\n" ); + ob_start(); + self::generateFeed( $rows, $feed ); + $cachedFeed = ob_get_contents(); + ob_end_flush(); + $this->saveToCache( $cachedFeed, $timekey, $key ); + } + return true; + } + + /** + * Save to feed result to $messageMemc + * + * @param string $feed Feed's content + * @param string $timekey Memcached key of the last modification + * @param string $key Memcached key of the content + */ + public function saveToCache( $feed, $timekey, $key ) { + global $messageMemc; + $expire = 3600 * 24; # One day + $messageMemc->set( $key, $feed, $expire ); + $messageMemc->set( $timekey, wfTimestamp( TS_MW ), $expire ); + } + + /** + * Try to load the feed result from $messageMemc + * + * @param int $lastmod Timestamp of the last item in the recentchanges table + * @param string $timekey Memcached key of the last modification + * @param string $key Memcached key of the content + * @return string|bool Feed's content on cache hit or false on cache miss + */ + public function loadFromCache( $lastmod, $timekey, $key ) { + global $wgFeedCacheTimeout, $wgOut, $messageMemc; + + $feedLastmod = $messageMemc->get( $timekey ); + + if ( ( $wgFeedCacheTimeout > 0 ) && $feedLastmod ) { + /** + * If the cached feed was rendered very recently, we may + * go ahead and use it even if there have been edits made + * since it was rendered. This keeps a swarm of requests + * from being too bad on a super-frequently edited wiki. + */ + + $feedAge = time() - wfTimestamp( TS_UNIX, $feedLastmod ); + $feedLastmodUnix = wfTimestamp( TS_UNIX, $feedLastmod ); + $lastmodUnix = wfTimestamp( TS_UNIX, $lastmod ); + + if ( $feedAge < $wgFeedCacheTimeout || $feedLastmodUnix > $lastmodUnix ) { + wfDebug( "RC: loading feed from cache ($key; $feedLastmod; $lastmod)...\n" ); + if ( $feedLastmodUnix < $lastmodUnix ) { + $wgOut->setLastModified( $feedLastmod ); // bug 21916 + } + return $messageMemc->get( $key ); + } else { + wfDebug( "RC: cached feed timestamp check failed ($feedLastmod; $lastmod)\n" ); + } + } + return false; + } + + /** + * Generate the feed items given a row from the database, printing the feed. + * @param object $rows DatabaseBase resource with recentchanges rows + * @param Feed $feed + */ + public static function generateFeed( $rows, &$feed ) { + wfProfileIn( __METHOD__ ); + $items = self::buildItems( $rows ); + $feed->outHeader(); + foreach ( $items as $item ) { + $feed->outItem( $item ); + } + $feed->outFooter(); + wfProfileOut( __METHOD__ ); + } + + /** + * Generate the feed items given a row from the database. + * @param object $rows DatabaseBase resource with recentchanges rows + */ + public static function buildItems( $rows ) { + wfProfileIn( __METHOD__ ); + $items = array(); + + # Merge adjacent edits by one user + $sorted = array(); + $n = 0; + foreach ( $rows as $obj ) { + if ( $n > 0 && + $obj->rc_type == RC_EDIT && + $obj->rc_namespace >= 0 && + $obj->rc_cur_id == $sorted[$n - 1]->rc_cur_id && + $obj->rc_user_text == $sorted[$n - 1]->rc_user_text ) { + $sorted[$n - 1]->rc_last_oldid = $obj->rc_last_oldid; + } else { + $sorted[$n] = $obj; + $n++; + } + } + + foreach ( $sorted as $obj ) { + $title = Title::makeTitle( $obj->rc_namespace, $obj->rc_title ); + $talkpage = MWNamespace::canTalk( $obj->rc_namespace ) + ? $title->getTalkPage()->getFullURL() + : ''; + + // Skip items with deleted content (avoids partially complete/inconsistent output) + if ( $obj->rc_deleted ) { + continue; + } + + if ( $obj->rc_this_oldid ) { + $url = $title->getFullURL( array( + 'diff' => $obj->rc_this_oldid, + 'oldid' => $obj->rc_last_oldid, + ) ); + } else { + // log entry or something like that. + $url = $title->getFullURL(); + } + + $items[] = new FeedItem( + $title->getPrefixedText(), + FeedUtils::formatDiff( $obj ), + $url, + $obj->rc_timestamp, + ( $obj->rc_deleted & Revision::DELETED_USER ) + ? wfMessage( 'rev-deleted-user' )->escaped() : $obj->rc_user_text, + $talkpage + ); + } + + wfProfileOut( __METHOD__ ); + return $items; + } +}