MediaWiki REL1_37
ApiQueryAllPages.php
Go to the documentation of this file.
1<?php
29
32
34 private $genderCache;
35
42 public function __construct(
43 ApiQuery $query,
44 $moduleName,
47 ) {
48 parent::__construct( $query, $moduleName, 'ap' );
49 $this->namespaceInfo = $namespaceInfo;
50 $this->genderCache = $genderCache;
51 }
52
53 public function execute() {
54 $this->run();
55 }
56
57 public function getCacheMode( $params ) {
58 return 'public';
59 }
60
65 public function executeGenerator( $resultPageSet ) {
66 if ( $resultPageSet->isResolvingRedirects() ) {
67 $this->dieWithError( 'apierror-allpages-generator-redirects', 'params' );
68 }
69
70 $this->run( $resultPageSet );
71 }
72
77 private function run( $resultPageSet = null ) {
78 $db = $this->getDB();
79
80 $params = $this->extractRequestParams();
81
82 // Page filters
83 $this->addTables( 'page' );
84
85 if ( $params['continue'] !== null ) {
86 $cont = explode( '|', $params['continue'] );
87 $this->dieContinueUsageIf( count( $cont ) != 1 );
88 $op = $params['dir'] == 'descending' ? '<' : '>';
89 $cont_from = $db->addQuotes( $cont[0] );
90 $this->addWhere( "page_title $op= $cont_from" );
91 }
92
93 $miserMode = $this->getConfig()->get( 'MiserMode' );
94 if ( !$miserMode ) {
95 if ( $params['filterredir'] == 'redirects' ) {
96 $this->addWhereFld( 'page_is_redirect', 1 );
97 } elseif ( $params['filterredir'] == 'nonredirects' ) {
98 $this->addWhereFld( 'page_is_redirect', 0 );
99 }
100 }
101
102 $this->addWhereFld( 'page_namespace', $params['namespace'] );
103 $dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' );
104 $from = ( $params['from'] === null
105 ? null
106 : $this->titlePartToKey( $params['from'], $params['namespace'] ) );
107 $to = ( $params['to'] === null
108 ? null
109 : $this->titlePartToKey( $params['to'], $params['namespace'] ) );
110 $this->addWhereRange( 'page_title', $dir, $from, $to );
111
112 if ( isset( $params['prefix'] ) ) {
113 $this->addWhere( 'page_title' . $db->buildLike(
114 $this->titlePartToKey( $params['prefix'], $params['namespace'] ),
115 $db->anyString() ) );
116 }
117
118 if ( $resultPageSet === null ) {
119 $selectFields = [
120 'page_namespace',
121 'page_title',
122 'page_id'
123 ];
124 } else {
125 $selectFields = $resultPageSet->getPageTableFields();
126 }
127
128 $miserModeFilterRedirValue = null;
129 $miserModeFilterRedir = $miserMode && $params['filterredir'] !== 'all';
130 if ( $miserModeFilterRedir ) {
131 $selectFields[] = 'page_is_redirect';
132
133 if ( $params['filterredir'] == 'redirects' ) {
134 $miserModeFilterRedirValue = 1;
135 } elseif ( $params['filterredir'] == 'nonredirects' ) {
136 $miserModeFilterRedirValue = 0;
137 }
138 }
139
140 $this->addFields( $selectFields );
141 $forceNameTitleIndex = true;
142 if ( isset( $params['minsize'] ) ) {
143 $this->addWhere( 'page_len>=' . (int)$params['minsize'] );
144 $forceNameTitleIndex = false;
145 }
146
147 if ( isset( $params['maxsize'] ) ) {
148 $this->addWhere( 'page_len<=' . (int)$params['maxsize'] );
149 $forceNameTitleIndex = false;
150 }
151
152 // Page protection filtering
153 if ( $params['prtype'] || $params['prexpiry'] != 'all' ) {
154 $this->addTables( 'page_restrictions' );
155 $this->addWhere( 'page_id=pr_page' );
156 $this->addWhere( "pr_expiry > {$db->addQuotes( $db->timestamp() )} OR pr_expiry IS NULL" );
157
158 if ( $params['prtype'] ) {
159 $this->addWhereFld( 'pr_type', $params['prtype'] );
160
161 if ( isset( $params['prlevel'] ) ) {
162 // Remove the empty string and '*' from the prlevel array
163 $prlevel = array_diff( $params['prlevel'], [ '', '*' ] );
164
165 if ( count( $prlevel ) ) {
166 $this->addWhereFld( 'pr_level', $prlevel );
167 }
168 }
169 if ( $params['prfiltercascade'] == 'cascading' ) {
170 $this->addWhereFld( 'pr_cascade', 1 );
171 } elseif ( $params['prfiltercascade'] == 'noncascading' ) {
172 $this->addWhereFld( 'pr_cascade', 0 );
173 }
174 }
175 $forceNameTitleIndex = false;
176
177 if ( $params['prexpiry'] == 'indefinite' ) {
178 $this->addWhere( "pr_expiry = {$db->addQuotes( $db->getInfinity() )} OR pr_expiry IS NULL" );
179 } elseif ( $params['prexpiry'] == 'definite' ) {
180 $this->addWhere( "pr_expiry != {$db->addQuotes( $db->getInfinity() )}" );
181 }
182
183 $this->addOption( 'DISTINCT' );
184 } elseif ( isset( $params['prlevel'] ) ) {
185 $this->dieWithError(
186 [ 'apierror-invalidparammix-mustusewith', 'prlevel', 'prtype' ], 'invalidparammix'
187 );
188 }
189
190 if ( $params['filterlanglinks'] == 'withoutlanglinks' ) {
191 $this->addTables( 'langlinks' );
192 $this->addJoinConds( [ 'langlinks' => [ 'LEFT JOIN', 'page_id=ll_from' ] ] );
193 $this->addWhere( 'll_from IS NULL' );
194 $forceNameTitleIndex = false;
195 } elseif ( $params['filterlanglinks'] == 'withlanglinks' ) {
196 $this->addTables( 'langlinks' );
197 $this->addWhere( 'page_id=ll_from' );
198 $this->addOption( 'STRAIGHT_JOIN' );
199
200 // MySQL filesorts if we use a GROUP BY that works with the rules
201 // in the 1992 SQL standard (it doesn't like having the
202 // constant-in-WHERE page_namespace column in there). Using the
203 // 1999 rules works fine, but that breaks other DBs. Sigh.
204 // @todo Once we drop support for 1992-rule DBs, we can simplify this.
205 $dbType = $db->getType();
206 if ( $dbType === 'mysql' || $dbType === 'sqlite' ) {
207 // Ignore the rules, or 1999 rules if you count unique keys
208 // over non-NULL columns as satisfying the requirement for
209 // "functional dependency" and don't require including
210 // constant-in-WHERE columns in the GROUP BY.
211 $this->addOption( 'GROUP BY', [ 'page_title' ] );
212 } elseif ( $dbType === 'postgres' && $db->getServerVersion() >= 9.1 ) {
213 // 1999 rules only counting primary keys
214 $this->addOption( 'GROUP BY', [ 'page_title', 'page_id' ] );
215 } else {
216 // 1992 rules
217 $this->addOption( 'GROUP BY', $selectFields );
218 }
219
220 $forceNameTitleIndex = false;
221 }
222
223 if ( $forceNameTitleIndex ) {
224 $this->addOption( 'USE INDEX', 'page_name_title' );
225 }
226
227 $limit = $params['limit'];
228 $this->addOption( 'LIMIT', $limit + 1 );
229 $res = $this->select( __METHOD__ );
230
231 // Get gender information
232 if ( $this->namespaceInfo->hasGenderDistinction( $params['namespace'] ) ) {
233 $users = [];
234 foreach ( $res as $row ) {
235 $users[] = $row->page_title;
236 }
237 $this->genderCache->doQuery( $users, __METHOD__ );
238 $res->rewind(); // reset
239 }
240
241 $count = 0;
242 $result = $this->getResult();
243 foreach ( $res as $row ) {
244 if ( ++$count > $limit ) {
245 // We've reached the one extra which shows that there are
246 // additional pages to be had. Stop here...
247 $this->setContinueEnumParameter( 'continue', $row->page_title );
248 break;
249 }
250
251 if ( $miserModeFilterRedir && (int)$row->page_is_redirect !== $miserModeFilterRedirValue ) {
252 // Filter implemented in PHP due to being in Miser Mode
253 continue;
254 }
255
256 if ( $resultPageSet === null ) {
257 $title = Title::makeTitle( $row->page_namespace, $row->page_title );
258 $vals = [
259 'pageid' => (int)$row->page_id,
260 'ns' => $title->getNamespace(),
261 'title' => $title->getPrefixedText()
262 ];
263 $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $vals );
264 if ( !$fit ) {
265 $this->setContinueEnumParameter( 'continue', $row->page_title );
266 break;
267 }
268 } else {
269 $resultPageSet->processDbRow( $row );
270 }
271 }
272
273 if ( $resultPageSet === null ) {
274 $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'p' );
275 }
276 }
277
278 public function getAllowedParams() {
279 $ret = [
280 'from' => null,
281 'continue' => [
282 ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
283 ],
284 'to' => null,
285 'prefix' => null,
286 'namespace' => [
288 ApiBase::PARAM_TYPE => 'namespace',
289 ],
290 'filterredir' => [
291 ApiBase::PARAM_DFLT => 'all',
293 'all',
294 'redirects',
295 'nonredirects'
296 ]
297 ],
298 'minsize' => [
299 ApiBase::PARAM_TYPE => 'integer',
300 ],
301 'maxsize' => [
302 ApiBase::PARAM_TYPE => 'integer',
303 ],
304 'prtype' => [
305 ApiBase::PARAM_TYPE => Title::getFilteredRestrictionTypes( true ),
307 ],
308 'prlevel' => [
309 ApiBase::PARAM_TYPE => $this->getConfig()->get( 'RestrictionLevels' ),
311 ],
312 'prfiltercascade' => [
313 ApiBase::PARAM_DFLT => 'all',
315 'cascading',
316 'noncascading',
317 'all'
318 ],
319 ],
320 'limit' => [
322 ApiBase::PARAM_TYPE => 'limit',
326 ],
327 'dir' => [
328 ApiBase::PARAM_DFLT => 'ascending',
330 'ascending',
331 'descending'
332 ]
333 ],
334 'filterlanglinks' => [
336 'withlanglinks',
337 'withoutlanglinks',
338 'all'
339 ],
340 ApiBase::PARAM_DFLT => 'all'
341 ],
342 'prexpiry' => [
344 'indefinite',
345 'definite',
346 'all'
347 ],
348 ApiBase::PARAM_DFLT => 'all'
349 ],
350 ];
351
352 if ( $this->getConfig()->get( 'MiserMode' ) ) {
353 $ret['filterredir'][ApiBase::PARAM_HELP_MSG_APPEND] = [ 'api-help-param-limited-in-miser-mode' ];
354 }
355
356 return $ret;
357 }
358
359 protected function getExamplesMessages() {
360 return [
361 'action=query&list=allpages&apfrom=B'
362 => 'apihelp-query+allpages-example-b',
363 'action=query&generator=allpages&gaplimit=4&gapfrom=T&prop=info'
364 => 'apihelp-query+allpages-example-generator',
365 'action=query&generator=allpages&gaplimit=2&' .
366 'gapfilterredir=nonredirects&gapfrom=Re&prop=revisions&rvprop=content'
367 => 'apihelp-query+allpages-example-generator-revisions',
368 ];
369 }
370
371 public function getHelpUrls() {
372 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Allpages';
373 }
374}
const NS_MAIN
Definition Defines.php:64
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1436
const PARAM_MAX2
Definition ApiBase.php:89
const PARAM_MAX
Definition ApiBase.php:85
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition ApiBase.php:1620
const PARAM_TYPE
Definition ApiBase.php:81
const PARAM_DFLT
Definition ApiBase.php:73
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
Definition ApiBase.php:169
const PARAM_MIN
Definition ApiBase.php:93
const LIMIT_BIG1
Fast query, standard limit.
Definition ApiBase.php:220
getResult()
Get the result object.
Definition ApiBase.php:628
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:764
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:162
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition ApiBase.php:222
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:497
const PARAM_ISMULTI
Definition ApiBase.php:77
Query module to enumerate all available pages.
NamespaceInfo $namespaceInfo
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
getCacheMode( $params)
Get the cache mode for the data generated by this module.
executeGenerator( $resultPageSet)
GenderCache $genderCache
run( $resultPageSet=null)
getHelpUrls()
Return links to more detailed help pages about the module.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
getExamplesMessages()
Returns usage examples for this module.
__construct(ApiQuery $query, $moduleName, NamespaceInfo $namespaceInfo, GenderCache $genderCache)
addWhereRange( $field, $dir, $start, $end, $sort=true)
Add a WHERE clause corresponding to a range, and an ORDER BY clause to sort in the right direction.
addFields( $value)
Add a set of fields to select to the internal array.
addOption( $name, $value=null)
Add an option such as LIMIT or USE INDEX.
addTables( $tables, $alias=null)
Add a set of tables to the internal array.
getDB()
Get the Query database connection (read-only)
select( $method, $extraQuery=[], array &$hookData=null)
Execute a SELECT query based on the values in the internal arrays.
addJoinConds( $join_conds)
Add a set of JOIN conditions to the internal array.
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
titlePartToKey( $titlePart, $namespace=NS_MAIN)
Convert an input title or title prefix into a dbkey.
addWhere( $value)
Add a set of WHERE clauses to the internal array.
setContinueEnumParameter( $paramName, $paramValue)
Overridden to set the generator param if in generator mode.
This is the main query class.
Definition ApiQuery.php:37
Caches user genders when needed to use correct namespace aliases.
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
return true
Definition router.php:92