MediaWiki
REL1_23
|
00001 <?php 00032 class ApiQueryAllPages extends ApiQueryGeneratorBase { 00033 00034 public function __construct( $query, $moduleName ) { 00035 parent::__construct( $query, $moduleName, 'ap' ); 00036 } 00037 00038 public function execute() { 00039 $this->run(); 00040 } 00041 00042 public function getCacheMode( $params ) { 00043 return 'public'; 00044 } 00045 00050 public function executeGenerator( $resultPageSet ) { 00051 if ( $resultPageSet->isResolvingRedirects() ) { 00052 $this->dieUsage( 00053 'Use "gapfilterredir=nonredirects" option instead of "redirects" ' . 00054 'when using allpages as a generator', 00055 'params' 00056 ); 00057 } 00058 00059 $this->run( $resultPageSet ); 00060 } 00061 00066 private function run( $resultPageSet = null ) { 00067 $db = $this->getDB(); 00068 00069 $params = $this->extractRequestParams(); 00070 00071 // Page filters 00072 $this->addTables( 'page' ); 00073 00074 if ( !is_null( $params['continue'] ) ) { 00075 $cont = explode( '|', $params['continue'] ); 00076 $this->dieContinueUsageIf( count( $cont ) != 1 ); 00077 $op = $params['dir'] == 'descending' ? '<' : '>'; 00078 $cont_from = $db->addQuotes( $cont[0] ); 00079 $this->addWhere( "page_title $op= $cont_from" ); 00080 } 00081 00082 if ( $params['filterredir'] == 'redirects' ) { 00083 $this->addWhereFld( 'page_is_redirect', 1 ); 00084 } elseif ( $params['filterredir'] == 'nonredirects' ) { 00085 $this->addWhereFld( 'page_is_redirect', 0 ); 00086 } 00087 00088 $this->addWhereFld( 'page_namespace', $params['namespace'] ); 00089 $dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' ); 00090 $from = ( $params['from'] === null 00091 ? null 00092 : $this->titlePartToKey( $params['from'], $params['namespace'] ) ); 00093 $to = ( $params['to'] === null 00094 ? null 00095 : $this->titlePartToKey( $params['to'], $params['namespace'] ) ); 00096 $this->addWhereRange( 'page_title', $dir, $from, $to ); 00097 00098 if ( isset( $params['prefix'] ) ) { 00099 $this->addWhere( 'page_title' . $db->buildLike( 00100 $this->titlePartToKey( $params['prefix'], $params['namespace'] ), 00101 $db->anyString() ) ); 00102 } 00103 00104 if ( is_null( $resultPageSet ) ) { 00105 $selectFields = array( 00106 'page_namespace', 00107 'page_title', 00108 'page_id' 00109 ); 00110 } else { 00111 $selectFields = $resultPageSet->getPageTableFields(); 00112 } 00113 00114 $this->addFields( $selectFields ); 00115 $forceNameTitleIndex = true; 00116 if ( isset( $params['minsize'] ) ) { 00117 $this->addWhere( 'page_len>=' . intval( $params['minsize'] ) ); 00118 $forceNameTitleIndex = false; 00119 } 00120 00121 if ( isset( $params['maxsize'] ) ) { 00122 $this->addWhere( 'page_len<=' . intval( $params['maxsize'] ) ); 00123 $forceNameTitleIndex = false; 00124 } 00125 00126 // Page protection filtering 00127 if ( count( $params['prtype'] ) || $params['prexpiry'] != 'all' ) { 00128 $this->addTables( 'page_restrictions' ); 00129 $this->addWhere( 'page_id=pr_page' ); 00130 $this->addWhere( "pr_expiry > {$db->addQuotes( $db->timestamp() )} OR pr_expiry IS NULL" ); 00131 00132 if ( count( $params['prtype'] ) ) { 00133 $this->addWhereFld( 'pr_type', $params['prtype'] ); 00134 00135 if ( isset( $params['prlevel'] ) ) { 00136 // Remove the empty string and '*' from the prlevel array 00137 $prlevel = array_diff( $params['prlevel'], array( '', '*' ) ); 00138 00139 if ( count( $prlevel ) ) { 00140 $this->addWhereFld( 'pr_level', $prlevel ); 00141 } 00142 } 00143 if ( $params['prfiltercascade'] == 'cascading' ) { 00144 $this->addWhereFld( 'pr_cascade', 1 ); 00145 } elseif ( $params['prfiltercascade'] == 'noncascading' ) { 00146 $this->addWhereFld( 'pr_cascade', 0 ); 00147 } 00148 } 00149 $forceNameTitleIndex = false; 00150 00151 if ( $params['prexpiry'] == 'indefinite' ) { 00152 $this->addWhere( "pr_expiry = {$db->addQuotes( $db->getInfinity() )} OR pr_expiry IS NULL" ); 00153 } elseif ( $params['prexpiry'] == 'definite' ) { 00154 $this->addWhere( "pr_expiry != {$db->addQuotes( $db->getInfinity() )}" ); 00155 } 00156 00157 $this->addOption( 'DISTINCT' ); 00158 } elseif ( isset( $params['prlevel'] ) ) { 00159 $this->dieUsage( 'prlevel may not be used without prtype', 'params' ); 00160 } 00161 00162 if ( $params['filterlanglinks'] == 'withoutlanglinks' ) { 00163 $this->addTables( 'langlinks' ); 00164 $this->addJoinConds( array( 'langlinks' => array( 'LEFT JOIN', 'page_id=ll_from' ) ) ); 00165 $this->addWhere( 'll_from IS NULL' ); 00166 $forceNameTitleIndex = false; 00167 } elseif ( $params['filterlanglinks'] == 'withlanglinks' ) { 00168 $this->addTables( 'langlinks' ); 00169 $this->addWhere( 'page_id=ll_from' ); 00170 $this->addOption( 'STRAIGHT_JOIN' ); 00171 // We have to GROUP BY all selected fields to stop 00172 // PostgreSQL from whining 00173 $this->addOption( 'GROUP BY', $selectFields ); 00174 $forceNameTitleIndex = false; 00175 } 00176 00177 if ( $forceNameTitleIndex ) { 00178 $this->addOption( 'USE INDEX', 'name_title' ); 00179 } 00180 00181 $limit = $params['limit']; 00182 $this->addOption( 'LIMIT', $limit + 1 ); 00183 $res = $this->select( __METHOD__ ); 00184 00185 //Get gender information 00186 if ( MWNamespace::hasGenderDistinction( $params['namespace'] ) ) { 00187 $users = array(); 00188 foreach ( $res as $row ) { 00189 $users[] = $row->page_title; 00190 } 00191 GenderCache::singleton()->doQuery( $users, __METHOD__ ); 00192 $res->rewind(); //reset 00193 } 00194 00195 $count = 0; 00196 $result = $this->getResult(); 00197 foreach ( $res as $row ) { 00198 if ( ++$count > $limit ) { 00199 // We've reached the one extra which shows that there are 00200 // additional pages to be had. Stop here... 00201 $this->setContinueEnumParameter( 'continue', $row->page_title ); 00202 break; 00203 } 00204 00205 if ( is_null( $resultPageSet ) ) { 00206 $title = Title::makeTitle( $row->page_namespace, $row->page_title ); 00207 $vals = array( 00208 'pageid' => intval( $row->page_id ), 00209 'ns' => intval( $title->getNamespace() ), 00210 'title' => $title->getPrefixedText() 00211 ); 00212 $fit = $result->addValue( array( 'query', $this->getModuleName() ), null, $vals ); 00213 if ( !$fit ) { 00214 $this->setContinueEnumParameter( 'continue', $row->page_title ); 00215 break; 00216 } 00217 } else { 00218 $resultPageSet->processDbRow( $row ); 00219 } 00220 } 00221 00222 if ( is_null( $resultPageSet ) ) { 00223 $result->setIndexedTagName_internal( array( 'query', $this->getModuleName() ), 'p' ); 00224 } 00225 } 00226 00227 public function getAllowedParams() { 00228 global $wgRestrictionLevels; 00229 00230 return array( 00231 'from' => null, 00232 'continue' => null, 00233 'to' => null, 00234 'prefix' => null, 00235 'namespace' => array( 00236 ApiBase::PARAM_DFLT => NS_MAIN, 00237 ApiBase::PARAM_TYPE => 'namespace', 00238 ), 00239 'filterredir' => array( 00240 ApiBase::PARAM_DFLT => 'all', 00241 ApiBase::PARAM_TYPE => array( 00242 'all', 00243 'redirects', 00244 'nonredirects' 00245 ) 00246 ), 00247 'minsize' => array( 00248 ApiBase::PARAM_TYPE => 'integer', 00249 ), 00250 'maxsize' => array( 00251 ApiBase::PARAM_TYPE => 'integer', 00252 ), 00253 'prtype' => array( 00254 ApiBase::PARAM_TYPE => Title::getFilteredRestrictionTypes( true ), 00255 ApiBase::PARAM_ISMULTI => true 00256 ), 00257 'prlevel' => array( 00258 ApiBase::PARAM_TYPE => $wgRestrictionLevels, 00259 ApiBase::PARAM_ISMULTI => true 00260 ), 00261 'prfiltercascade' => array( 00262 ApiBase::PARAM_DFLT => 'all', 00263 ApiBase::PARAM_TYPE => array( 00264 'cascading', 00265 'noncascading', 00266 'all' 00267 ), 00268 ), 00269 'limit' => array( 00270 ApiBase::PARAM_DFLT => 10, 00271 ApiBase::PARAM_TYPE => 'limit', 00272 ApiBase::PARAM_MIN => 1, 00273 ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1, 00274 ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2 00275 ), 00276 'dir' => array( 00277 ApiBase::PARAM_DFLT => 'ascending', 00278 ApiBase::PARAM_TYPE => array( 00279 'ascending', 00280 'descending' 00281 ) 00282 ), 00283 'filterlanglinks' => array( 00284 ApiBase::PARAM_TYPE => array( 00285 'withlanglinks', 00286 'withoutlanglinks', 00287 'all' 00288 ), 00289 ApiBase::PARAM_DFLT => 'all' 00290 ), 00291 'prexpiry' => array( 00292 ApiBase::PARAM_TYPE => array( 00293 'indefinite', 00294 'definite', 00295 'all' 00296 ), 00297 ApiBase::PARAM_DFLT => 'all' 00298 ), 00299 ); 00300 } 00301 00302 public function getParamDescription() { 00303 $p = $this->getModulePrefix(); 00304 00305 return array( 00306 'from' => 'The page title to start enumerating from', 00307 'continue' => 'When more results are available, use this to continue', 00308 'to' => 'The page title to stop enumerating at', 00309 'prefix' => 'Search for all page titles that begin with this value', 00310 'namespace' => 'The namespace to enumerate', 00311 'filterredir' => 'Which pages to list', 00312 'dir' => 'The direction in which to list', 00313 'minsize' => 'Limit to pages with at least this many bytes', 00314 'maxsize' => 'Limit to pages with at most this many bytes', 00315 'prtype' => 'Limit to protected pages only', 00316 'prlevel' => "The protection level (must be used with {$p}prtype= parameter)", 00317 'prfiltercascade' 00318 => "Filter protections based on cascadingness (ignored when {$p}prtype isn't set)", 00319 'filterlanglinks' => array( 00320 'Filter based on whether a page has langlinks', 00321 'Note that this may not consider langlinks added by extensions.', 00322 ), 00323 'limit' => 'How many total pages to return.', 00324 'prexpiry' => array( 00325 'Which protection expiry to filter the page on', 00326 ' indefinite - Get only pages with indefinite protection expiry', 00327 ' definite - Get only pages with a definite (specific) protection expiry', 00328 ' all - Get pages with any protections expiry' 00329 ), 00330 ); 00331 } 00332 00333 public function getResultProperties() { 00334 return array( 00335 '' => array( 00336 'pageid' => 'integer', 00337 'ns' => 'namespace', 00338 'title' => 'string' 00339 ) 00340 ); 00341 } 00342 00343 public function getDescription() { 00344 return 'Enumerate all pages sequentially in a given namespace.'; 00345 } 00346 00347 public function getPossibleErrors() { 00348 return array_merge( parent::getPossibleErrors(), array( 00349 array( 00350 'code' => 'params', 00351 'info' => 'Use "gapfilterredir=nonredirects" option instead of ' . 00352 '"redirects" when using allpages as a generator' 00353 ), 00354 array( 'code' => 'params', 'info' => 'prlevel may not be used without prtype' ), 00355 ) ); 00356 } 00357 00358 public function getExamples() { 00359 return array( 00360 'api.php?action=query&list=allpages&apfrom=B' => array( 00361 'Simple Use', 00362 'Show a list of pages starting at the letter "B"', 00363 ), 00364 'api.php?action=query&generator=allpages&gaplimit=4&gapfrom=T&prop=info' => array( 00365 'Using as Generator', 00366 'Show info about 4 pages starting at the letter "T"', 00367 ), 00368 'api.php?action=query&generator=allpages&gaplimit=2&' . 00369 'gapfilterredir=nonredirects&gapfrom=Re&prop=revisions&rvprop=content' 00370 => array( 'Show content of first 2 non-redirect pages beginning at "Re"' ) 00371 ); 00372 } 00373 00374 public function getHelpUrls() { 00375 return 'https://www.mediawiki.org/wiki/API:Allpages'; 00376 } 00377 }