MediaWiki
REL1_23
|
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 ( !wfRunHooks( 'SpecialRecentChangesQuery', 00113 array( &$conds, &$tables, &$join_conds, $opts, &$query_options, &$select ), 00114 '1.23' ) 00115 ) { 00116 return false; 00117 } 00118 00119 if ( $ns == NS_CATEGORY && !$showlinkedto ) { 00120 // special handling for categories 00121 // XXX: should try to make this less kludgy 00122 $link_tables = array( 'categorylinks' ); 00123 $showlinkedto = true; 00124 } else { 00125 // for now, always join on these tables; really should be configurable as in whatlinkshere 00126 $link_tables = array( 'pagelinks', 'templatelinks' ); 00127 // imagelinks only contains links to pages in NS_FILE 00128 if ( $ns == NS_FILE || !$showlinkedto ) { 00129 $link_tables[] = 'imagelinks'; 00130 } 00131 } 00132 00133 if ( $id == 0 && !$showlinkedto ) { 00134 return false; // nonexistent pages can't link to any pages 00135 } 00136 00137 // field name prefixes for all the various tables we might want to join with 00138 $prefix = array( 00139 'pagelinks' => 'pl', 00140 'templatelinks' => 'tl', 00141 'categorylinks' => 'cl', 00142 'imagelinks' => 'il' 00143 ); 00144 00145 $subsql = array(); // SELECT statements to combine with UNION 00146 00147 foreach ( $link_tables as $link_table ) { 00148 $pfx = $prefix[$link_table]; 00149 00150 // imagelinks and categorylinks tables have no xx_namespace field, 00151 // and have xx_to instead of xx_title 00152 if ( $link_table == 'imagelinks' ) { 00153 $link_ns = NS_FILE; 00154 } elseif ( $link_table == 'categorylinks' ) { 00155 $link_ns = NS_CATEGORY; 00156 } else { 00157 $link_ns = 0; 00158 } 00159 00160 if ( $showlinkedto ) { 00161 // find changes to pages linking to this page 00162 if ( $link_ns ) { 00163 if ( $ns != $link_ns ) { 00164 continue; 00165 } // should never happen, but check anyway 00166 $subconds = array( "{$pfx}_to" => $dbkey ); 00167 } else { 00168 $subconds = array( "{$pfx}_namespace" => $ns, "{$pfx}_title" => $dbkey ); 00169 } 00170 $subjoin = "rc_cur_id = {$pfx}_from"; 00171 } else { 00172 // find changes to pages linked from this page 00173 $subconds = array( "{$pfx}_from" => $id ); 00174 if ( $link_table == 'imagelinks' || $link_table == 'categorylinks' ) { 00175 $subconds["rc_namespace"] = $link_ns; 00176 $subjoin = "rc_title = {$pfx}_to"; 00177 } else { 00178 $subjoin = array( "rc_namespace = {$pfx}_namespace", "rc_title = {$pfx}_title" ); 00179 } 00180 } 00181 00182 if ( $dbr->unionSupportsOrderAndLimit() ) { 00183 $order = array( 'ORDER BY' => 'rc_timestamp DESC' ); 00184 } else { 00185 $order = array(); 00186 } 00187 00188 $query = $dbr->selectSQLText( 00189 array_merge( $tables, array( $link_table ) ), 00190 $select, 00191 $conds + $subconds, 00192 __METHOD__, 00193 $order + $query_options, 00194 $join_conds + array( $link_table => array( 'INNER JOIN', $subjoin ) ) 00195 ); 00196 00197 if ( $dbr->unionSupportsOrderAndLimit() ) { 00198 $query = $dbr->limitResult( $query, $limit ); 00199 } 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 00224 function setTopText( FormOptions $opts ) { 00225 $target = $this->getTargetTitle(); 00226 if ( $target ) { 00227 $this->getOutput()->addBacklinkSubtitle( $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 }