X-Git-Url: https://scripts.mit.edu/gitweb/autoinstallsdev/mediawiki.git/blobdiff_plain/19e297c21b10b1b8a3acad5e73fc71dcb35db44a..6932310fd58ebef145fa01eb76edf7150284d8ea:/includes/specials/SpecialRecentchangeslinked.php diff --git a/includes/specials/SpecialRecentchangeslinked.php b/includes/specials/SpecialRecentchangeslinked.php index db0f554d..a13af55d 100644 --- a/includes/specials/SpecialRecentchangeslinked.php +++ b/includes/specials/SpecialRecentchangeslinked.php @@ -26,10 +26,11 @@ * * @ingroup SpecialPage */ -class SpecialRecentchangeslinked extends SpecialRecentChanges { - var $rclTargetTitle; +class SpecialRecentChangesLinked extends SpecialRecentChanges { + /** @var bool|Title */ + protected $rclTargetTitle; - function __construct(){ + function __construct() { parent::__construct( 'Recentchangeslinked' ); } @@ -37,7 +38,7 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { $opts = parent::getDefaultOptions(); $opts->add( 'target', '' ); $opts->add( 'showlinkedto', false ); - $opts->add( 'tagfilter', '' ); + return $opts; } @@ -45,25 +46,12 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { $opts['target'] = $par; } - public function feedSetup() { - global $wgRequest; - $opts = parent::feedSetup(); - $opts['target'] = $wgRequest->getVal( 'target' ); - return $opts; - } - - public function getFeedObject( $feedFormat ){ - $feed = new ChangesFeed( $feedFormat, false ); - $feedObj = $feed->getFeedObject( - wfMsgForContent( 'recentchangeslinked-title', $this->getTargetTitle()->getPrefixedText() ), - wfMsgForContent( 'recentchangeslinked-feed' ) - ); - return array( $feed, $feedObj ); - } - - public function doMainQuery( $conds, $opts ) { - global $wgUser, $wgOut; - + /** + * @inheritDoc + */ + protected function doMainQuery( $tables, $select, $conds, $query_options, + $join_conds, FormOptions $opts + ) { $target = $opts['target']; $showlinkedto = $opts['showlinkedto']; $limit = $opts['limit']; @@ -71,13 +59,16 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { if ( $target === '' ) { return false; } - $title = Title::newFromURL( $target ); - if( !$title || $title->getInterwiki() != '' ){ - $wgOut->wrapWikiMsg( "
\n$1\n

", 'allpagesbadtitle' ); + $outputPage = $this->getOutput(); + $title = Title::newFromText( $target ); + if ( !$title || $title->isExternal() ) { + $outputPage->addHTML( '
' . $this->msg( 'allpagesbadtitle' ) + ->parse() . '
' ); + return false; } - $wgOut->setPageTitle( wfMsg( 'recentchangeslinked-title', $title->getPrefixedText() ) ); + $outputPage->setPageTitle( $this->msg( 'recentchangeslinked-title', $title->getPrefixedText() ) ); /* * Ordinary links are in the pagelinks table, while transclusions are @@ -88,137 +79,193 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { * expects only one result set so we use UNION instead. */ - $dbr = wfGetDB( DB_SLAVE, 'recentchangeslinked' ); - $id = $title->getArticleId(); + $dbr = wfGetDB( DB_REPLICA, 'recentchangeslinked' ); + $id = $title->getArticleID(); $ns = $title->getNamespace(); $dbkey = $title->getDBkey(); - $tables = array( 'recentchanges' ); - $select = array( $dbr->tableName( 'recentchanges' ) . '.*' ); - $join_conds = array(); - $query_options = array(); + $tables[] = 'recentchanges'; + $select = array_merge( RecentChange::selectFields(), $select ); // left join with watchlist table to highlight watched rows - $uid = $wgUser->getId(); - if( $uid ) { + $uid = $this->getUser()->getId(); + if ( $uid && $this->getUser()->isAllowed( 'viewmywatchlist' ) ) { $tables[] = 'watchlist'; $select[] = 'wl_user'; - $join_conds['watchlist'] = array( 'LEFT JOIN', "wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace" ); + $join_conds['watchlist'] = [ 'LEFT JOIN', [ + 'wl_user' => $uid, + 'wl_title=rc_title', + 'wl_namespace=rc_namespace' + ] ]; } - if ( $wgUser->isAllowed( 'rollback' ) ) { - $tables[] = 'page'; - $join_conds['page'] = array('LEFT JOIN', 'rc_cur_id=page_id'); - $select[] = 'page_latest'; - } - if ( !$this->including() ) { // bug 23293 - ChangeTags::modifyDisplayQuery( $tables, $select, $conds, $join_conds, - $query_options, $opts['tagfilter'] ); + + // JOIN on page, used for 'last revision' filter highlight + $tables[] = 'page'; + $join_conds['page'] = [ 'LEFT JOIN', 'rc_cur_id=page_id' ]; + $select[] = 'page_latest'; + + $tagFilter = $opts['tagfilter'] ? explode( '|', $opts['tagfilter'] ) : []; + ChangeTags::modifyDisplayQuery( + $tables, + $select, + $conds, + $join_conds, + $query_options, + $tagFilter + ); + + if ( $dbr->unionSupportsOrderAndLimit() ) { + if ( count( $tagFilter ) > 1 ) { + // ChangeTags::modifyDisplayQuery() will have added DISTINCT. + // To prevent this from causing query performance problems, we need to add + // a GROUP BY, and add rc_id to the ORDER BY. + $order = [ + 'GROUP BY' => 'rc_timestamp, rc_id', + 'ORDER BY' => 'rc_timestamp DESC, rc_id DESC' + ]; + } else { + $order = [ 'ORDER BY' => 'rc_timestamp DESC' ]; + } + } else { + $order = []; } - if ( !wfRunHooks( 'SpecialRecentChangesQuery', array( &$conds, &$tables, &$join_conds, $opts, &$query_options, &$select ) ) ) + if ( !$this->runMainQueryHook( $tables, $select, $conds, $query_options, $join_conds, + $opts ) + ) { return false; + } - if( $ns == NS_CATEGORY && !$showlinkedto ) { + if ( $ns == NS_CATEGORY && !$showlinkedto ) { // special handling for categories - // XXX: should try to make this less klugy - $link_tables = array( 'categorylinks' ); + // XXX: should try to make this less kludgy + $link_tables = [ 'categorylinks' ]; $showlinkedto = true; } else { // for now, always join on these tables; really should be configurable as in whatlinkshere - $link_tables = array( 'pagelinks', 'templatelinks' ); + $link_tables = [ 'pagelinks', 'templatelinks' ]; // imagelinks only contains links to pages in NS_FILE - if( $ns == NS_FILE || !$showlinkedto ) $link_tables[] = 'imagelinks'; + if ( $ns == NS_FILE || !$showlinkedto ) { + $link_tables[] = 'imagelinks'; + } } - if( $id == 0 && !$showlinkedto ) + if ( $id == 0 && !$showlinkedto ) { return false; // nonexistent pages can't link to any pages + } // field name prefixes for all the various tables we might want to join with - $prefix = array( 'pagelinks' => 'pl', 'templatelinks' => 'tl', 'categorylinks' => 'cl', 'imagelinks' => 'il' ); + $prefix = [ + 'pagelinks' => 'pl', + 'templatelinks' => 'tl', + 'categorylinks' => 'cl', + 'imagelinks' => 'il' + ]; - $subsql = array(); // SELECT statements to combine with UNION + $subsql = []; // SELECT statements to combine with UNION - foreach( $link_tables as $link_table ) { + foreach ( $link_tables as $link_table ) { $pfx = $prefix[$link_table]; - // imagelinks and categorylinks tables have no xx_namespace field, and have xx_to instead of xx_title - if( $link_table == 'imagelinks' ) $link_ns = NS_FILE; - else if( $link_table == 'categorylinks' ) $link_ns = NS_CATEGORY; - else $link_ns = 0; + // imagelinks and categorylinks tables have no xx_namespace field, + // and have xx_to instead of xx_title + if ( $link_table == 'imagelinks' ) { + $link_ns = NS_FILE; + } elseif ( $link_table == 'categorylinks' ) { + $link_ns = NS_CATEGORY; + } else { + $link_ns = 0; + } - if( $showlinkedto ) { + if ( $showlinkedto ) { // find changes to pages linking to this page - if( $link_ns ) { - if( $ns != $link_ns ) continue; // should never happen, but check anyway - $subconds = array( "{$pfx}_to" => $dbkey ); + if ( $link_ns ) { + if ( $ns != $link_ns ) { + continue; + } // should never happen, but check anyway + $subconds = [ "{$pfx}_to" => $dbkey ]; } else { - $subconds = array( "{$pfx}_namespace" => $ns, "{$pfx}_title" => $dbkey ); + $subconds = [ "{$pfx}_namespace" => $ns, "{$pfx}_title" => $dbkey ]; } $subjoin = "rc_cur_id = {$pfx}_from"; } else { // find changes to pages linked from this page - $subconds = array( "{$pfx}_from" => $id ); - if( $link_table == 'imagelinks' || $link_table == 'categorylinks' ) { + $subconds = [ "{$pfx}_from" => $id ]; + if ( $link_table == 'imagelinks' || $link_table == 'categorylinks' ) { $subconds["rc_namespace"] = $link_ns; $subjoin = "rc_title = {$pfx}_to"; } else { - $subjoin = "rc_namespace = {$pfx}_namespace AND rc_title = {$pfx}_title"; + $subjoin = [ "rc_namespace = {$pfx}_namespace", "rc_title = {$pfx}_title" ]; } } - if( $dbr->unionSupportsOrderAndLimit()) - $order = array( 'ORDER BY' => 'rc_timestamp DESC' ); - else - $order = array(); - - - $query = $dbr->selectSQLText( - array_merge( $tables, array( $link_table ) ), - $select, + $query = $dbr->selectSQLText( + array_merge( $tables, [ $link_table ] ), + $select, $conds + $subconds, - __METHOD__, + __METHOD__, $order + $query_options, - $join_conds + array( $link_table => array( 'INNER JOIN', $subjoin ) ) + $join_conds + [ $link_table => [ 'INNER JOIN', $subjoin ] ] ); - - if( $dbr->unionSupportsOrderAndLimit()) + + if ( $dbr->unionSupportsOrderAndLimit() ) { $query = $dbr->limitResult( $query, $limit ); + } $subsql[] = $query; } - if( count($subsql) == 0 ) + if ( count( $subsql ) == 0 ) { return false; // should never happen - if( count($subsql) == 1 && $dbr->unionSupportsOrderAndLimit() ) + } + if ( count( $subsql ) == 1 && $dbr->unionSupportsOrderAndLimit() ) { $sql = $subsql[0]; - else { + } else { // need to resort and relimit after union - $sql = $dbr->unionQueries($subsql, false).' ORDER BY rc_timestamp DESC'; - $sql = $dbr->limitResult($sql, $limit, false); + $sql = $dbr->unionQueries( $subsql, false ) . ' ORDER BY rc_timestamp DESC'; + $sql = $dbr->limitResult( $sql, $limit, false ); } - + $res = $dbr->query( $sql, __METHOD__ ); - if( $res->numRows() == 0 ) + if ( $res->numRows() == 0 ) { $this->mResultEmpty = true; + } return $res; } - - function getExtraOptions( $opts ){ - $opts->consumeValues( array( 'showlinkedto', 'target', 'tagfilter' ) ); - $extraOpts = array(); - $extraOpts['namespace'] = $this->namespaceFilterForm( $opts ); - $extraOpts['target'] = array( wfMsgHtml( 'recentchangeslinked-page' ), - Xml::input( 'target', 40, str_replace('_',' ',$opts['target']) ) . - Xml::check( 'showlinkedto', $opts['showlinkedto'], array('id' => 'showlinkedto') ) . ' ' . - Xml::label( wfMsg("recentchangeslinked-to"), 'showlinkedto' ) ); - $tagFilter = ChangeTags::buildTagFilterSelector( $opts['tagfilter'] ); - if ($tagFilter) - $extraOpts['tagfilter'] = $tagFilter; + + function setTopText( FormOptions $opts ) { + $target = $this->getTargetTitle(); + if ( $target ) { + $this->getOutput()->addBacklinkSubtitle( $target ); + $this->getSkin()->setRelevantTitle( $target ); + } + } + + /** + * Get options to be displayed in a form + * + * @param FormOptions $opts + * @return array + */ + function getExtraOptions( $opts ) { + $extraOpts = parent::getExtraOptions( $opts ); + + $opts->consumeValues( [ 'showlinkedto', 'target' ] ); + + $extraOpts['target'] = [ $this->msg( 'recentchangeslinked-page' )->escaped(), + Xml::input( 'target', 40, str_replace( '_', ' ', $opts['target'] ) ) . + Xml::check( 'showlinkedto', $opts['showlinkedto'], [ 'id' => 'showlinkedto' ] ) . ' ' . + Xml::label( $this->msg( 'recentchangeslinked-to' )->text(), 'showlinkedto' ) ]; + + $this->addHelpLink( 'Help:Related changes' ); return $extraOpts; } + /** + * @return Title + */ function getTargetTitle() { if ( $this->rclTargetTitle === null ) { $opts = $this->getOptions(); @@ -228,30 +275,19 @@ class SpecialRecentchangeslinked extends SpecialRecentChanges { $this->rclTargetTitle = false; } } - return $this->rclTargetTitle; - } - - function setTopText( OutputPage $out, FormOptions $opts ) { - global $wgUser; - $skin = $wgUser->getSkin(); - $target = $this->getTargetTitle(); - if( $target ) - $out->setSubtitle( wfMsg( 'recentchangeslinked-backlink', $skin->link( $target, - $target->getPrefixedText(), array(), array( 'redirect' => 'no' ) ) ) ); - } - public function getFeedQuery() { - $target = $this->getTargetTitle(); - if( $target ) { - return "target=" . urlencode( $target->getPrefixedDBkey() ); - } else { - return false; - } + return $this->rclTargetTitle; } - function setBottomText( OutputPage $out, FormOptions $opts ) { - if( isset( $this->mResultEmpty ) && $this->mResultEmpty ){ - $out->addWikiMsg( 'recentchangeslinked-noresult' ); - } + /** + * Return an array of subpages beginning with $search that this special page will accept. + * + * @param string $search Prefix to search for + * @param int $limit Maximum number of results to return (usually 10) + * @param int $offset Number of results to skip (usually 0) + * @return string[] Matching subpages + */ + public function prefixSearchSubpages( $search, $limit, $offset ) { + return $this->prefixSearchString( $search, $limit, $offset ); } }