MediaWiki
REL1_24
|
00001 <?php 00032 class ApiQueryAllLinks extends ApiQueryGeneratorBase { 00033 00034 private $table, $tablePrefix, $indexTag, 00035 $description, $descriptionWhat, $descriptionTargets, $descriptionLinking; 00036 private $fieldTitle = 'title'; 00037 private $dfltNamespace = NS_MAIN; 00038 private $hasNamespace = true; 00039 private $useIndex = null; 00040 private $props = array(), $propHelp = array(); 00041 00042 public function __construct( ApiQuery $query, $moduleName ) { 00043 switch ( $moduleName ) { 00044 case 'alllinks': 00045 $prefix = 'al'; 00046 $this->table = 'pagelinks'; 00047 $this->tablePrefix = 'pl_'; 00048 $this->useIndex = 'pl_namespace'; 00049 $this->indexTag = 'l'; 00050 $this->description = 'Enumerate all links that point to a given namespace'; 00051 $this->descriptionWhat = 'link'; 00052 $this->descriptionTargets = 'linked titles'; 00053 $this->descriptionLinking = 'linking'; 00054 break; 00055 case 'alltransclusions': 00056 $prefix = 'at'; 00057 $this->table = 'templatelinks'; 00058 $this->tablePrefix = 'tl_'; 00059 $this->dfltNamespace = NS_TEMPLATE; 00060 $this->useIndex = 'tl_namespace'; 00061 $this->indexTag = 't'; 00062 $this->description = 00063 'List all transclusions (pages embedded using {{x}}), including non-existing'; 00064 $this->descriptionWhat = 'transclusion'; 00065 $this->descriptionTargets = 'transcluded titles'; 00066 $this->descriptionLinking = 'transcluding'; 00067 break; 00068 case 'allfileusages': 00069 $prefix = 'af'; 00070 $this->table = 'imagelinks'; 00071 $this->tablePrefix = 'il_'; 00072 $this->fieldTitle = 'to'; 00073 $this->dfltNamespace = NS_FILE; 00074 $this->hasNamespace = false; 00075 $this->indexTag = 'f'; 00076 $this->description = 'List all file usages, including non-existing'; 00077 $this->descriptionWhat = 'file'; 00078 $this->descriptionTargets = 'file titles'; 00079 $this->descriptionLinking = 'using'; 00080 break; 00081 case 'allredirects': 00082 $prefix = 'ar'; 00083 $this->table = 'redirect'; 00084 $this->tablePrefix = 'rd_'; 00085 $this->indexTag = 'r'; 00086 $this->description = 'List all redirects to a namespace'; 00087 $this->descriptionWhat = 'redirect'; 00088 $this->descriptionTargets = 'target pages'; 00089 $this->descriptionLinking = 'redirecting'; 00090 $this->props = array( 00091 'fragment' => 'rd_fragment', 00092 'interwiki' => 'rd_interwiki', 00093 ); 00094 $this->propHelp = array( 00095 ' fragment - Adds the fragment from the redirect, if any', 00096 ' interwiki - Adds the interwiki prefix from the redirect, if any', 00097 ); 00098 break; 00099 default: 00100 ApiBase::dieDebug( __METHOD__, 'Unknown module name' ); 00101 } 00102 00103 parent::__construct( $query, $moduleName, $prefix ); 00104 } 00105 00106 public function execute() { 00107 $this->run(); 00108 } 00109 00110 public function getCacheMode( $params ) { 00111 return 'public'; 00112 } 00113 00114 public function executeGenerator( $resultPageSet ) { 00115 $this->run( $resultPageSet ); 00116 } 00117 00122 private function run( $resultPageSet = null ) { 00123 $db = $this->getDB(); 00124 $params = $this->extractRequestParams(); 00125 00126 $pfx = $this->tablePrefix; 00127 $fieldTitle = $this->fieldTitle; 00128 $prop = array_flip( $params['prop'] ); 00129 $fld_ids = isset( $prop['ids'] ); 00130 $fld_title = isset( $prop['title'] ); 00131 if ( $this->hasNamespace ) { 00132 $namespace = $params['namespace']; 00133 } else { 00134 $namespace = $this->dfltNamespace; 00135 } 00136 00137 if ( $params['unique'] ) { 00138 $matches = array_intersect_key( $prop, $this->props + array( 'ids' => 1 ) ); 00139 if ( $matches ) { 00140 $p = $this->getModulePrefix(); 00141 $this->dieUsage( 00142 "Cannot use {$p}prop=" . join( '|', array_keys( $matches ) ) . " with {$p}unique", 00143 'params' 00144 ); 00145 } 00146 $this->addOption( 'DISTINCT' ); 00147 } 00148 00149 $this->addTables( $this->table ); 00150 if ( $this->hasNamespace ) { 00151 $this->addWhereFld( $pfx . 'namespace', $namespace ); 00152 } 00153 00154 $continue = !is_null( $params['continue'] ); 00155 if ( $continue ) { 00156 $continueArr = explode( '|', $params['continue'] ); 00157 $op = $params['dir'] == 'descending' ? '<' : '>'; 00158 if ( $params['unique'] ) { 00159 $this->dieContinueUsageIf( count( $continueArr ) != 1 ); 00160 $continueTitle = $db->addQuotes( $continueArr[0] ); 00161 $this->addWhere( "{$pfx}{$fieldTitle} $op= $continueTitle" ); 00162 } else { 00163 $this->dieContinueUsageIf( count( $continueArr ) != 2 ); 00164 $continueTitle = $db->addQuotes( $continueArr[0] ); 00165 $continueFrom = intval( $continueArr[1] ); 00166 $this->addWhere( 00167 "{$pfx}{$fieldTitle} $op $continueTitle OR " . 00168 "({$pfx}{$fieldTitle} = $continueTitle AND " . 00169 "{$pfx}from $op= $continueFrom)" 00170 ); 00171 } 00172 } 00173 00174 // 'continue' always overrides 'from' 00175 $from = ( $continue || $params['from'] === null ? null : 00176 $this->titlePartToKey( $params['from'], $namespace ) ); 00177 $to = ( $params['to'] === null ? null : 00178 $this->titlePartToKey( $params['to'], $namespace ) ); 00179 $this->addWhereRange( $pfx . $fieldTitle, 'newer', $from, $to ); 00180 00181 if ( isset( $params['prefix'] ) ) { 00182 $this->addWhere( $pfx . $fieldTitle . $db->buildLike( $this->titlePartToKey( 00183 $params['prefix'], $namespace ), $db->anyString() ) ); 00184 } 00185 00186 $this->addFields( array( 'pl_title' => $pfx . $fieldTitle ) ); 00187 $this->addFieldsIf( array( 'pl_from' => $pfx . 'from' ), !$params['unique'] ); 00188 foreach ( $this->props as $name => $field ) { 00189 $this->addFieldsIf( $field, isset( $prop[$name] ) ); 00190 } 00191 00192 if ( $this->useIndex ) { 00193 $this->addOption( 'USE INDEX', $this->useIndex ); 00194 } 00195 $limit = $params['limit']; 00196 $this->addOption( 'LIMIT', $limit + 1 ); 00197 00198 $sort = ( $params['dir'] == 'descending' ? ' DESC' : '' ); 00199 $orderBy = array(); 00200 $orderBy[] = $pfx . $fieldTitle . $sort; 00201 if ( !$params['unique'] ) { 00202 $orderBy[] = $pfx . 'from' . $sort; 00203 } 00204 $this->addOption( 'ORDER BY', $orderBy ); 00205 00206 $res = $this->select( __METHOD__ ); 00207 00208 $pageids = array(); 00209 $titles = array(); 00210 $count = 0; 00211 $result = $this->getResult(); 00212 foreach ( $res as $row ) { 00213 if ( ++$count > $limit ) { 00214 // We've reached the one extra which shows that there are 00215 // additional pages to be had. Stop here... 00216 if ( $params['unique'] ) { 00217 $this->setContinueEnumParameter( 'continue', $row->pl_title ); 00218 } else { 00219 $this->setContinueEnumParameter( 'continue', $row->pl_title . '|' . $row->pl_from ); 00220 } 00221 break; 00222 } 00223 00224 if ( is_null( $resultPageSet ) ) { 00225 $vals = array(); 00226 if ( $fld_ids ) { 00227 $vals['fromid'] = intval( $row->pl_from ); 00228 } 00229 if ( $fld_title ) { 00230 $title = Title::makeTitle( $namespace, $row->pl_title ); 00231 ApiQueryBase::addTitleInfo( $vals, $title ); 00232 } 00233 foreach ( $this->props as $name => $field ) { 00234 if ( isset( $prop[$name] ) && $row->$field !== null && $row->$field !== '' ) { 00235 $vals[$name] = $row->$field; 00236 } 00237 } 00238 $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $vals ); 00239 if ( !$fit ) { 00240 if ( $params['unique'] ) { 00241 $this->setContinueEnumParameter( 'continue', $row->pl_title ); 00242 } else { 00243 $this->setContinueEnumParameter( 'continue', $row->pl_title . '|' . $row->pl_from ); 00244 } 00245 break; 00246 } 00247 } elseif ( $params['unique'] ) { 00248 $titles[] = Title::makeTitle( $namespace, $row->pl_title ); 00249 } else { 00250 $pageids[] = $row->pl_from; 00251 } 00252 } 00253 00254 if ( is_null( $resultPageSet ) ) { 00255 $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), $this->indexTag ); 00256 } elseif ( $params['unique'] ) { 00257 $resultPageSet->populateFromTitles( $titles ); 00258 } else { 00259 $resultPageSet->populateFromPageIDs( $pageids ); 00260 } 00261 } 00262 00263 public function getAllowedParams() { 00264 $allowedParams = array( 00265 'continue' => null, 00266 'from' => null, 00267 'to' => null, 00268 'prefix' => null, 00269 'unique' => false, 00270 'prop' => array( 00271 ApiBase::PARAM_ISMULTI => true, 00272 ApiBase::PARAM_DFLT => 'title', 00273 ApiBase::PARAM_TYPE => array_merge( 00274 array( 'ids', 'title' ), array_keys( $this->props ) 00275 ), 00276 ), 00277 'namespace' => array( 00278 ApiBase::PARAM_DFLT => $this->dfltNamespace, 00279 ApiBase::PARAM_TYPE => 'namespace' 00280 ), 00281 'limit' => array( 00282 ApiBase::PARAM_DFLT => 10, 00283 ApiBase::PARAM_TYPE => 'limit', 00284 ApiBase::PARAM_MIN => 1, 00285 ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1, 00286 ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2 00287 ), 00288 'dir' => array( 00289 ApiBase::PARAM_DFLT => 'ascending', 00290 ApiBase::PARAM_TYPE => array( 00291 'ascending', 00292 'descending' 00293 ) 00294 ), 00295 ); 00296 if ( !$this->hasNamespace ) { 00297 unset( $allowedParams['namespace'] ); 00298 } 00299 00300 return $allowedParams; 00301 } 00302 00303 public function getParamDescription() { 00304 $p = $this->getModulePrefix(); 00305 $what = $this->descriptionWhat; 00306 $targets = $this->descriptionTargets; 00307 $linking = $this->descriptionLinking; 00308 $paramDescription = array( 00309 'from' => "The title of the $what to start enumerating from", 00310 'to' => "The title of the $what to stop enumerating at", 00311 'prefix' => "Search for all $targets that begin with this value", 00312 'unique' => array( 00313 "Only show distinct $targets. Cannot be used with {$p}prop=" . 00314 join( '|', array_keys( array( 'ids' => 1 ) + $this->props ) ) . '.', 00315 'When used as a generator, yields target pages instead of source pages.', 00316 ), 00317 'prop' => array( 00318 'What pieces of information to include', 00319 " ids - Adds the pageid of the $linking page (Cannot be used with {$p}unique)", 00320 " title - Adds the title of the $what", 00321 ), 00322 'namespace' => 'The namespace to enumerate', 00323 'limit' => 'How many total items to return', 00324 'continue' => 'When more results are available, use this to continue', 00325 'dir' => 'The direction in which to list', 00326 ); 00327 foreach ( $this->propHelp as $help ) { 00328 $paramDescription['prop'][] = "$help (Cannot be used with {$p}unique)"; 00329 } 00330 if ( !$this->hasNamespace ) { 00331 unset( $paramDescription['namespace'] ); 00332 } 00333 00334 return $paramDescription; 00335 } 00336 00337 public function getDescription() { 00338 return $this->description; 00339 } 00340 00341 public function getExamples() { 00342 $p = $this->getModulePrefix(); 00343 $name = $this->getModuleName(); 00344 $what = $this->descriptionWhat; 00345 $targets = $this->descriptionTargets; 00346 00347 return array( 00348 "api.php?action=query&list={$name}&{$p}from=B&{$p}prop=ids|title" 00349 => "List $targets with page ids they are from, including missing ones. Start at B", 00350 "api.php?action=query&list={$name}&{$p}unique=&{$p}from=B" 00351 => "List unique $targets", 00352 "api.php?action=query&generator={$name}&g{$p}unique=&g{$p}from=B" 00353 => "Gets all $targets, marking the missing ones", 00354 "api.php?action=query&generator={$name}&g{$p}from=B" 00355 => "Gets pages containing the {$what}s", 00356 ); 00357 } 00358 00359 public function getHelpUrls() { 00360 $name = ucfirst( $this->getModuleName() ); 00361 00362 return "https://www.mediawiki.org/wiki/API:{$name}"; 00363 } 00364 }