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