MediaWiki
REL1_22
|
00001 <?php 00029 class SpecialRecentchangeslinked extends SpecialRecentChanges { 00030 var $rclTargetTitle; 00031 00032 function __construct() { 00033 parent::__construct( 'Recentchangeslinked' ); 00034 } 00035 00036 public function getDefaultOptions() { 00037 $opts = parent::getDefaultOptions(); 00038 $opts->add( 'target', '' ); 00039 $opts->add( 'showlinkedto', false ); 00040 return $opts; 00041 } 00042 00043 public function parseParameters( $par, FormOptions $opts ) { 00044 $opts['target'] = $par; 00045 } 00046 00047 public function feedSetup() { 00048 $opts = parent::feedSetup(); 00049 $opts['target'] = $this->getRequest()->getVal( 'target' ); 00050 return $opts; 00051 } 00052 00053 public function getFeedObject( $feedFormat ) { 00054 $feed = new ChangesFeed( $feedFormat, false ); 00055 $feedObj = $feed->getFeedObject( 00056 $this->msg( 'recentchangeslinked-title', $this->getTargetTitle()->getPrefixedText() ) 00057 ->inContentLanguage()->text(), 00058 $this->msg( 'recentchangeslinked-feed' )->inContentLanguage()->text(), 00059 $this->getTitle()->getFullURL() 00060 ); 00061 return array( $feed, $feedObj ); 00062 } 00063 00064 public function doMainQuery( $conds, $opts ) { 00065 $target = $opts['target']; 00066 $showlinkedto = $opts['showlinkedto']; 00067 $limit = $opts['limit']; 00068 00069 if ( $target === '' ) { 00070 return false; 00071 } 00072 $outputPage = $this->getOutput(); 00073 $title = Title::newFromURL( $target ); 00074 if ( !$title || $title->getInterwiki() != '' ) { 00075 $outputPage->wrapWikiMsg( "<div class=\"errorbox\">\n$1\n</div>", 'allpagesbadtitle' ); 00076 return false; 00077 } 00078 00079 $outputPage->setPageTitle( $this->msg( 'recentchangeslinked-title', $title->getPrefixedText() ) ); 00080 00081 /* 00082 * Ordinary links are in the pagelinks table, while transclusions are 00083 * in the templatelinks table, categorizations in categorylinks and 00084 * image use in imagelinks. We need to somehow combine all these. 00085 * Special:Whatlinkshere does this by firing multiple queries and 00086 * merging the results, but the code we inherit from our parent class 00087 * expects only one result set so we use UNION instead. 00088 */ 00089 00090 $dbr = wfGetDB( DB_SLAVE, 'recentchangeslinked' ); 00091 $id = $title->getArticleID(); 00092 $ns = $title->getNamespace(); 00093 $dbkey = $title->getDBkey(); 00094 00095 $tables = array( 'recentchanges' ); 00096 $select = RecentChange::selectFields(); 00097 $join_conds = array(); 00098 $query_options = array(); 00099 00100 // left join with watchlist table to highlight watched rows 00101 $uid = $this->getUser()->getId(); 00102 if ( $uid && $this->getUser()->isAllowed( 'viewmywatchlist' ) ) { 00103 $tables[] = 'watchlist'; 00104 $select[] = 'wl_user'; 00105 $join_conds['watchlist'] = array( 'LEFT JOIN', array( 00106 'wl_user' => $uid, 00107 'wl_title=rc_title', 00108 'wl_namespace=rc_namespace' 00109 )); 00110 } 00111 if ( $this->getUser()->isAllowed( 'rollback' ) ) { 00112 $tables[] = 'page'; 00113 $join_conds['page'] = array( 'LEFT JOIN', 'rc_cur_id=page_id' ); 00114 $select[] = 'page_latest'; 00115 } 00116 ChangeTags::modifyDisplayQuery( 00117 $tables, 00118 $select, 00119 $conds, 00120 $join_conds, 00121 $query_options, 00122 $opts['tagfilter'] 00123 ); 00124 00125 if ( !wfRunHooks( 'SpecialRecentChangesQuery', array( &$conds, &$tables, &$join_conds, $opts, &$query_options, &$select ) ) ) { 00126 return false; 00127 } 00128 00129 if ( $ns == NS_CATEGORY && !$showlinkedto ) { 00130 // special handling for categories 00131 // XXX: should try to make this less kludgy 00132 $link_tables = array( 'categorylinks' ); 00133 $showlinkedto = true; 00134 } else { 00135 // for now, always join on these tables; really should be configurable as in whatlinkshere 00136 $link_tables = array( 'pagelinks', 'templatelinks' ); 00137 // imagelinks only contains links to pages in NS_FILE 00138 if ( $ns == NS_FILE || !$showlinkedto ) { 00139 $link_tables[] = 'imagelinks'; 00140 } 00141 } 00142 00143 if ( $id == 0 && !$showlinkedto ) { 00144 return false; // nonexistent pages can't link to any pages 00145 } 00146 00147 // field name prefixes for all the various tables we might want to join with 00148 $prefix = array( 'pagelinks' => 'pl', 'templatelinks' => 'tl', 'categorylinks' => 'cl', 'imagelinks' => 'il' ); 00149 00150 $subsql = array(); // SELECT statements to combine with UNION 00151 00152 foreach ( $link_tables as $link_table ) { 00153 $pfx = $prefix[$link_table]; 00154 00155 // imagelinks and categorylinks tables have no xx_namespace field, and have xx_to instead of xx_title 00156 if ( $link_table == 'imagelinks' ) { 00157 $link_ns = NS_FILE; 00158 } elseif ( $link_table == 'categorylinks' ) { 00159 $link_ns = NS_CATEGORY; 00160 } else { 00161 $link_ns = 0; 00162 } 00163 00164 if ( $showlinkedto ) { 00165 // find changes to pages linking to this page 00166 if ( $link_ns ) { 00167 if ( $ns != $link_ns ) { 00168 continue; 00169 } // should never happen, but check anyway 00170 $subconds = array( "{$pfx}_to" => $dbkey ); 00171 } else { 00172 $subconds = array( "{$pfx}_namespace" => $ns, "{$pfx}_title" => $dbkey ); 00173 } 00174 $subjoin = "rc_cur_id = {$pfx}_from"; 00175 } else { 00176 // find changes to pages linked from this page 00177 $subconds = array( "{$pfx}_from" => $id ); 00178 if ( $link_table == 'imagelinks' || $link_table == 'categorylinks' ) { 00179 $subconds["rc_namespace"] = $link_ns; 00180 $subjoin = "rc_title = {$pfx}_to"; 00181 } else { 00182 $subjoin = array( "rc_namespace = {$pfx}_namespace", "rc_title = {$pfx}_title" ); 00183 } 00184 } 00185 00186 if ( $dbr->unionSupportsOrderAndLimit() ) { 00187 $order = array( 'ORDER BY' => 'rc_timestamp DESC' ); 00188 } else { 00189 $order = array(); 00190 } 00191 00192 $query = $dbr->selectSQLText( 00193 array_merge( $tables, array( $link_table ) ), 00194 $select, 00195 $conds + $subconds, 00196 __METHOD__, 00197 $order + $query_options, 00198 $join_conds + array( $link_table => array( 'INNER JOIN', $subjoin ) ) 00199 ); 00200 00201 if ( $dbr->unionSupportsOrderAndLimit() ) { 00202 $query = $dbr->limitResult( $query, $limit ); 00203 } 00204 00205 $subsql[] = $query; 00206 } 00207 00208 if ( count( $subsql ) == 0 ) { 00209 return false; // should never happen 00210 } 00211 if ( count( $subsql ) == 1 && $dbr->unionSupportsOrderAndLimit() ) { 00212 $sql = $subsql[0]; 00213 } else { 00214 // need to resort and relimit after union 00215 $sql = $dbr->unionQueries( $subsql, false ) . ' ORDER BY rc_timestamp DESC'; 00216 $sql = $dbr->limitResult( $sql, $limit, false ); 00217 } 00218 00219 $res = $dbr->query( $sql, __METHOD__ ); 00220 00221 if ( $res->numRows() == 0 ) { 00222 $this->mResultEmpty = true; 00223 } 00224 00225 return $res; 00226 } 00227 00234 function getExtraOptions( $opts ) { 00235 $extraOpts = parent::getExtraOptions( $opts ); 00236 00237 $opts->consumeValues( array( 'showlinkedto', 'target' ) ); 00238 00239 $extraOpts['target'] = array( $this->msg( 'recentchangeslinked-page' )->escaped(), 00240 Xml::input( 'target', 40, str_replace( '_', ' ', $opts['target'] ) ) . 00241 Xml::check( 'showlinkedto', $opts['showlinkedto'], array( 'id' => 'showlinkedto' ) ) . ' ' . 00242 Xml::label( $this->msg( 'recentchangeslinked-to' )->text(), 'showlinkedto' ) ); 00243 00244 return $extraOpts; 00245 } 00246 00250 function getTargetTitle() { 00251 if ( $this->rclTargetTitle === null ) { 00252 $opts = $this->getOptions(); 00253 if ( isset( $opts['target'] ) && $opts['target'] !== '' ) { 00254 $this->rclTargetTitle = Title::newFromText( $opts['target'] ); 00255 } else { 00256 $this->rclTargetTitle = false; 00257 } 00258 } 00259 return $this->rclTargetTitle; 00260 } 00261 00262 function setTopText( FormOptions $opts ) { 00263 $target = $this->getTargetTitle(); 00264 if ( $target ) { 00265 $this->getOutput()->addBacklinkSubtitle( $target ); 00266 } 00267 } 00268 }