X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fspecials%2FSpecialRecentchanges.php;h=2f13fe590a944068eeaadeccfc877ae2089802a1;hb=b56197b7bab6e589a0ed068e493c08652eec4f5d;hp=78843a802a74ddb53e5a8f77f2fded5e802621af;hpb=94cdb82e2d7a90d6f1770a72671cc7c60a2a3b54;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/specials/SpecialRecentchanges.php b/includes/specials/SpecialRecentchanges.php index 78843a802a..2f13fe590a 100644 --- a/includes/specials/SpecialRecentchanges.php +++ b/includes/specials/SpecialRecentchanges.php @@ -1,13 +1,36 @@ includable( true ); + +/** + * A special page that lists last changes made to the wiki + * + * @ingroup SpecialPage + */ +class SpecialRecentChanges extends IncludableSpecialPage { + var $rcOptions, $rcSubpage; + + public function __construct( $name = 'Recentchanges' ) { + parent::__construct( $name ); } /** @@ -40,7 +63,7 @@ class SpecialRecentChanges extends SpecialPage { } /** - * Get a FormOptions object with options as specified by the user + * Create a FormOptions object with options as specified by the user * * @return FormOptions */ @@ -55,31 +78,45 @@ class SpecialRecentChanges extends SpecialPage { $this->parseParameters( $parameters, $opts ); } - $opts->validateIntBounds( 'limit', 0, 500 ); + $opts->validateIntBounds( 'limit', 0, 5000 ); return $opts; } /** - * Get a FormOptions object sepcific for feed requests + * Create a FormOptions object specific for feed requests and return it * * @return FormOptions */ public function feedSetup() { global $wgFeedLimit, $wgRequest; $opts = $this->getDefaultOptions(); - # Feed is cached on limit,hideminor; other params would randomly not work - $opts->fetchValuesFromRequest( $wgRequest, array( 'limit', 'hideminor' ) ); + # Feed is cached on limit,hideminor,namespace; other params would randomly not work + $opts->fetchValuesFromRequest( $wgRequest, array( 'limit', 'hideminor', 'namespace' ) ); $opts->validateIntBounds( 'limit', 0, $wgFeedLimit ); return $opts; } + /** + * Get the current FormOptions for this request + */ + public function getOptions() { + if ( $this->rcOptions === null ) { + global $wgRequest; + $feedFormat = $wgRequest->getVal( 'feed' ); + $this->rcOptions = $feedFormat ? $this->feedSetup() : $this->setup( $this->rcSubpage ); + } + return $this->rcOptions; + } + + /** * Main execution point * - * @param $parameters string + * @param $subpage String */ - public function execute( $parameters ) { + public function execute( $subpage ) { global $wgRequest, $wgOut; + $this->rcSubpage = $subpage; $feedFormat = $wgRequest->getVal( 'feed' ); # 10 seconds server-side caching max @@ -90,12 +127,11 @@ class SpecialRecentChanges extends SpecialPage { return; } - $opts = $feedFormat ? $this->feedSetup() : $this->setup( $parameters ); + $opts = $this->getOptions(); $this->setHeaders(); $this->outputHeader(); // Fetch results, prepare a batch link existence check query - $rows = array(); $conds = $this->buildMainQueryConds( $opts ); $rows = $this->doMainQuery( $conds, $opts ); if( $rows === false ){ @@ -114,10 +150,9 @@ class SpecialRecentChanges extends SpecialPage { } $batch->execute(); } - $target = isset($opts['target']) ? $opts['target'] : ''; // RCL has targets if( $feedFormat ) { - list( $feed, $feedObj ) = $this->getFeedObject( $feedFormat ); - $feed->execute( $feedObj, $rows, $opts['limit'], $opts['hideminor'], $lastmod, $target ); + list( $changesFeed, $formatter ) = $this->getFeedObject( $feedFormat ); + $changesFeed->execute( $formatter, $rows, $lastmod, $opts ); } else { $this->webOutput( $rows, $opts ); } @@ -128,15 +163,15 @@ class SpecialRecentChanges extends SpecialPage { /** * Return an array with a ChangesFeed object and ChannelFeed object * - * @return array + * @return Array */ public function getFeedObject( $feedFormat ){ - $feed = new ChangesFeed( $feedFormat, 'rcfeed' ); - $feedObj = $feed->getFeedObject( + $changesFeed = new ChangesFeed( $feedFormat, 'rcfeed' ); + $formatter = $changesFeed->getFeedObject( wfMsgForContent( 'recentchanges' ), wfMsgForContent( 'recentchanges-feed-description' ) ); - return array( $feed, $feedObj ); + return array( $changesFeed, $formatter ); } /** @@ -172,12 +207,12 @@ class SpecialRecentChanges extends SpecialPage { * update the timestamp * * @param $feedFormat String - * @return string or false + * @return String or false */ public function checkLastModified( $feedFormat ) { global $wgUseRCPatrol, $wgOut; $dbr = wfGetDB( DB_SLAVE ); - $lastmod = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', false, __FUNCTION__ ); + $lastmod = $dbr->selectField( 'recentchanges', 'MAX(rc_timestamp)', false, __METHOD__ ); if( $feedFormat || !$wgUseRCPatrol ) { if( $lastmod && $wgOut->checkLastModified( $lastmod ) ) { # Client cache fresh and headers sent, nothing more to do. @@ -261,7 +296,7 @@ class SpecialRecentChanges extends SpecialPage { /** * Process the query * - * @param $conds array + * @param $conds Array * @param $opts FormOptions * @return database result or false (for Recentchangeslinked only) */ @@ -276,10 +311,9 @@ class SpecialRecentChanges extends SpecialPage { $dbr = wfGetDB( DB_SLAVE ); $limit = $opts['limit']; $namespace = $opts['namespace']; + $select = '*'; $invert = $opts['invert']; - $join_conds = array(); - // JOIN on watchlist for users if( $uid ) { $tables[] = 'watchlist'; @@ -290,23 +324,29 @@ class SpecialRecentChanges extends SpecialPage { $tables[] = 'page'; $join_conds['page'] = array('LEFT JOIN', 'rc_cur_id=page_id'); } - // Tag stuff. - $fields = array(); - // Fields are * in this case, so let the function modify an empty array to keep it happy. - ChangeTags::modifyDisplayQuery( $tables, - $fields, - $conds, - $join_conds, - $query_options, - $opts['tagfilter'] - ); - - wfRunHooks('SpecialRecentChangesQuery', array( &$conds, &$tables, &$join_conds, $opts ) ); - - // Is there either one namespace selected or excluded? - // Tag filtering also has a better index. - // Also, if this is "all" or main namespace, just use timestamp index. - if( is_null($namespace) || $invert || $opts['tagfilter'] ) { + if ( !$this->including() ) { + // Tag stuff. + // Doesn't work when transcluding. See bug 23293 + $fields = array(); + // Fields are * in this case, so let the function modify an empty array to keep it happy. + ChangeTags::modifyDisplayQuery( + $tables, $fields, $conds, $join_conds, $query_options, $opts['tagfilter'] + ); + } + + if ( !wfRunHooks( 'SpecialRecentChangesQuery', array( &$conds, &$tables, &$join_conds, $opts, &$query_options, &$select ) ) ) + return false; + + // Don't use the new_namespace_time timestamp index if: + // (a) "All namespaces" selected + // (b) We want all pages NOT in a certain namespaces (inverted) + // (c) There is a tag to filter on (use tag index instead) + // (d) UNION + sort/limit is not an option for the DBMS + if( is_null( $namespace ) + || ( $invert && !is_null( $namespace ) ) + || $opts['tagfilter'] != '' + || !$dbr->unionSupportsOrderAndLimit() ) + { $res = $dbr->select( $tables, '*', $conds, __METHOD__, array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit ) + $query_options, @@ -314,21 +354,22 @@ class SpecialRecentChanges extends SpecialPage { // We have a new_namespace_time index! UNION over new=(0,1) and sort result set! } else { // New pages - $sqlNew = $dbr->selectSQLText( $tables, '*', + $sqlNew = $dbr->selectSQLText( $tables, $select, array( 'rc_new' => 1 ) + $conds, __METHOD__, array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit, - 'USE INDEX' => array('recentchanges' => 'new_name_timestamp') ), + 'USE INDEX' => array('recentchanges' => 'rc_timestamp') ), $join_conds ); // Old pages $sqlOld = $dbr->selectSQLText( $tables, '*', array( 'rc_new' => 0 ) + $conds, __METHOD__, array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit, - 'USE INDEX' => array('recentchanges' => 'new_name_timestamp') ), + 'USE INDEX' => array('recentchanges' => 'rc_timestamp') ), $join_conds ); # Join the two fast queries, and sort the result set - $sql = "($sqlNew) UNION ($sqlOld) ORDER BY rc_timestamp DESC LIMIT $limit"; + $sql = $dbr->unionQueries(array($sqlNew, $sqlOld), false).' ORDER BY rc_timestamp DESC'; + $sql = $dbr->limitResult($sql, $limit, false); $res = $dbr->query( $sql, __METHOD__ ); } @@ -338,7 +379,7 @@ class SpecialRecentChanges extends SpecialPage { /** * Send output to $wgOut, only called if not used feeds * - * @param $rows array of database rows + * @param $rows Array of database rows * @param $opts FormOptions */ public function webOutput( $rows, $opts ) { @@ -353,7 +394,7 @@ class SpecialRecentChanges extends SpecialPage { } // And now for the content - $wgOut->setSyndicated( true ); + $wgOut->setFeedAppendQuery( $this->getFeedQuery() ); if( $wgAllowCategorizedRecentChanges ) { $this->filterByCategories( $rows, $opts ); @@ -400,6 +441,14 @@ class SpecialRecentChanges extends SpecialPage { $wgOut->addHTML( $s ); } + /** + * Get the query string to append to feed link URLs. + * This is overridden by RCL to add the target parameter + */ + public function getFeedQuery() { + return false; + } + /** * Return the text to be displayed above the changes * @@ -413,7 +462,8 @@ class SpecialRecentChanges extends SpecialPage { $defaults = $opts->getAllValues(); $nondefaults = $opts->getChangedValues(); - $opts->consumeValues( array( 'namespace', 'invert' ) ); + $opts->consumeValues( array( 'namespace', 'invert', 'tagfilter', + 'categories', 'categories_any' ) ); $panel = array(); $panel[] = $this->optionsPanel( $defaults, $nondefaults ); @@ -443,11 +493,11 @@ class SpecialRecentChanges extends SpecialPage { $unconsumed = $opts->getUnconsumedValues(); foreach( $unconsumed as $key => $value ) { - $out .= Xml::hidden( $key, $value ); + $out .= Html::hidden( $key, $value ); } $t = $this->getTitle(); - $out .= Xml::hidden( 'title', $t->getPrefixedText() ); + $out .= Html::hidden( 'title', $t->getPrefixedText() ); $form = Xml::tags( 'form', array( 'action' => $wgScript ), $out ); $panel[] = $form; $panelString = implode( "\n", $panel ); @@ -463,7 +513,7 @@ class SpecialRecentChanges extends SpecialPage { * Get options to be displayed in a form * * @param $opts FormOptions - * @return array + * @return Array */ function getExtraOptions( $opts ){ $extraOpts = array(); @@ -505,7 +555,7 @@ class SpecialRecentChanges extends SpecialPage { * Creates the choose namespace selection * * @param $opts FormOptions - * @return string + * @return String */ protected function namespaceFilterForm( FormOptions $opts ) { $nsSelect = Xml::namespaceSelector( $opts['namespace'], '' ); @@ -518,7 +568,7 @@ class SpecialRecentChanges extends SpecialPage { * Create a input to filter changes by categories * * @param $opts FormOptions - * @return array + * @return Array */ protected function categoryFilterForm( FormOptions $opts ) { list( $label, $input ) = Xml::inputLabelSep( wfMsg('rc_categories'), @@ -533,13 +583,13 @@ class SpecialRecentChanges extends SpecialPage { /** * Filter $rows by categories set in $opts * - * @param $rows array of database rows + * @param $rows Array of database rows * @param $opts FormOptions */ function filterByCategories( &$rows, FormOptions $opts ) { - $categories = array_map( 'trim', explode( "|" , $opts['categories'] ) ); + $categories = array_map( 'trim', explode( '|' , $opts['categories'] ) ); - if( empty($categories) ) { + if( !count( $categories ) ) { return; } @@ -547,32 +597,34 @@ class SpecialRecentChanges extends SpecialPage { $cats = array(); foreach( $categories as $cat ) { $cat = trim( $cat ); - if( $cat == "" ) continue; + if( $cat == '' ) continue; $cats[] = $cat; } # Filter articles $articles = array(); $a2r = array(); + $rowsarr = array(); foreach( $rows AS $k => $r ) { $nt = Title::makeTitle( $r->rc_namespace, $r->rc_title ); $id = $nt->getArticleID(); if( $id == 0 ) continue; # Page might have been deleted... - if( !in_array($id, $articles) ) { + if( !in_array( $id, $articles ) ) { $articles[] = $id; } - if( !isset($a2r[$id]) ) { + if( !isset( $a2r[$id] ) ) { $a2r[$id] = array(); } $a2r[$id][] = $k; + $rowsarr[$k] = $r; } # Shortcut? - if( !count($articles) || !count($cats) ) + if( !count( $articles ) || !count( $cats ) ) return ; # Look up - $c = new Categoryfinder ; + $c = new Categoryfinder; $c->seed( $articles, $cats, $opts['categories_any'] ? "OR" : "AND" ) ; $match = $c->run(); @@ -581,7 +633,7 @@ class SpecialRecentChanges extends SpecialPage { foreach( $match AS $id ) { foreach( $a2r[$id] AS $rev ) { $k = $rev; - $newrows[$k] = $rows[$k]; + $newrows[$k] = $rowsarr[$k]; } } $rows = $newrows; @@ -589,9 +641,11 @@ class SpecialRecentChanges extends SpecialPage { /** * Makes change an option link which carries all the other options - * @param $title see Title - * @param $override - * @param $options + * + * @param $title Title + * @param $override Array: options to override + * @param $options Array: current options + * @param $active Boolean: whether to show the link in bold */ function makeOptionsLink( $title, $override, $options, $active = false ) { global $wgUser; @@ -607,8 +661,9 @@ class SpecialRecentChanges extends SpecialPage { /** * Creates the options panel. - * @param $defaults array - * @param $nondefaults array + * + * @param $defaults Array + * @param $nondefaults Array */ function optionsPanel( $defaults, $nondefaults ) { global $wgLang, $wgUser, $wgRCLinkLimits, $wgRCLinkDays; @@ -616,13 +671,15 @@ class SpecialRecentChanges extends SpecialPage { $options = $nondefaults + $defaults; $note = ''; - if( !wfEmptyMsg( 'rclegend', wfMsg('rclegend') ) ) { + if( !wfEmptyMsg( 'rclegend' ) ) { $note .= '
' . wfMsgExt( 'rclegend', array('parseinline') ) . "
\n"; } if( $options['from'] ) { $note .= wfMsgExt( 'rcnotefrom', array( 'parseinline' ), $wgLang->formatNum( $options['limit'] ), - $wgLang->timeanddate( $options['from'], true ) ) . '
'; + $wgLang->timeanddate( $options['from'], true ), + $wgLang->date( $options['from'], true ), + $wgLang->time( $options['from'], true ) ) . '
'; } # Sort data for display and make sure it's unique after we've added user data.