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