MediaWiki master
ApiQueryAllPages.php
Go to the documentation of this file.
1<?php
23namespace MediaWiki\Api;
24
34
41
42 private NamespaceInfo $namespaceInfo;
43 private GenderCache $genderCache;
44 private RestrictionStore $restrictionStore;
45
46 public function __construct(
47 ApiQuery $query,
48 string $moduleName,
49 NamespaceInfo $namespaceInfo,
50 GenderCache $genderCache,
51 RestrictionStore $restrictionStore
52 ) {
53 parent::__construct( $query, $moduleName, 'ap' );
54 $this->namespaceInfo = $namespaceInfo;
55 $this->genderCache = $genderCache;
56 $this->restrictionStore = $restrictionStore;
57 }
58
59 public function execute() {
60 $this->run();
61 }
62
63 public function getCacheMode( $params ) {
64 return 'public';
65 }
66
71 public function executeGenerator( $resultPageSet ) {
72 if ( $resultPageSet->isResolvingRedirects() ) {
73 $this->dieWithError( 'apierror-allpages-generator-redirects', 'params' );
74 }
75
76 $this->run( $resultPageSet );
77 }
78
83 private function run( $resultPageSet = null ) {
84 $db = $this->getDB();
85
86 $params = $this->extractRequestParams();
87
88 // Page filters
89 $this->addTables( 'page' );
90
91 if ( $params['continue'] !== null ) {
92 $cont = $this->parseContinueParamOrDie( $params['continue'], [ 'string' ] );
93 $op = $params['dir'] == 'descending' ? '<=' : '>=';
94 $this->addWhere( $db->expr( 'page_title', $op, $cont[0] ) );
95 }
96
97 $miserMode = $this->getConfig()->get( MainConfigNames::MiserMode );
98 if ( !$miserMode ) {
99 if ( $params['filterredir'] == 'redirects' ) {
100 $this->addWhereFld( 'page_is_redirect', 1 );
101 } elseif ( $params['filterredir'] == 'nonredirects' ) {
102 $this->addWhereFld( 'page_is_redirect', 0 );
103 }
104 }
105
106 $this->addWhereFld( 'page_namespace', $params['namespace'] );
107 $dir = ( $params['dir'] == 'descending' ? 'older' : 'newer' );
108 $from = ( $params['from'] === null
109 ? null
110 : $this->titlePartToKey( $params['from'], $params['namespace'] ) );
111 $to = ( $params['to'] === null
112 ? null
113 : $this->titlePartToKey( $params['to'], $params['namespace'] ) );
114 $this->addWhereRange( 'page_title', $dir, $from, $to );
115
116 if ( isset( $params['prefix'] ) ) {
117 $this->addWhere(
118 $db->expr(
119 'page_title',
120 IExpression::LIKE,
121 new LikeValue( $this->titlePartToKey( $params['prefix'], $params['namespace'] ), $db->anyString() )
122 )
123 );
124 }
125
126 if ( $resultPageSet === null ) {
127 $selectFields = [
128 'page_namespace',
129 'page_title',
130 'page_id'
131 ];
132 } else {
133 $selectFields = $resultPageSet->getPageTableFields();
134 }
135
136 $miserModeFilterRedirValue = null;
137 $miserModeFilterRedir = $miserMode && $params['filterredir'] !== 'all';
138 if ( $miserModeFilterRedir ) {
139 $selectFields[] = 'page_is_redirect';
140
141 if ( $params['filterredir'] == 'redirects' ) {
142 $miserModeFilterRedirValue = 1;
143 } elseif ( $params['filterredir'] == 'nonredirects' ) {
144 $miserModeFilterRedirValue = 0;
145 }
146 }
147
148 $this->addFields( $selectFields );
149 $forceNameTitleIndex = true;
150 if ( isset( $params['minsize'] ) ) {
151 $this->addWhere( 'page_len>=' . (int)$params['minsize'] );
152 $forceNameTitleIndex = false;
153 }
154
155 if ( isset( $params['maxsize'] ) ) {
156 $this->addWhere( 'page_len<=' . (int)$params['maxsize'] );
157 $forceNameTitleIndex = false;
158 }
159
160 // Page protection filtering
161 if ( $params['prtype'] || $params['prexpiry'] != 'all' ) {
162 $this->addTables( 'page_restrictions' );
163 $this->addWhere( 'page_id=pr_page' );
164 $this->addWhere(
165 $db->expr( 'pr_expiry', '>', $db->timestamp() )->or( 'pr_expiry', '=', null )
166 );
167
168 if ( $params['prtype'] ) {
169 $this->addWhereFld( 'pr_type', $params['prtype'] );
170
171 if ( isset( $params['prlevel'] ) ) {
172 // Remove the empty string and '*' from the prlevel array
173 $prlevel = array_diff( $params['prlevel'], [ '', '*' ] );
174
175 if ( count( $prlevel ) ) {
176 $this->addWhereFld( 'pr_level', $prlevel );
177 }
178 }
179 if ( $params['prfiltercascade'] == 'cascading' ) {
180 $this->addWhereFld( 'pr_cascade', 1 );
181 } elseif ( $params['prfiltercascade'] == 'noncascading' ) {
182 $this->addWhereFld( 'pr_cascade', 0 );
183 }
184 }
185 $forceNameTitleIndex = false;
186
187 if ( $params['prexpiry'] == 'indefinite' ) {
188 $this->addWhereFld( 'pr_expiry', [ $db->getInfinity(), null ] );
189 } elseif ( $params['prexpiry'] == 'definite' ) {
190 $this->addWhere( $db->expr( 'pr_expiry', '!=', $db->getInfinity() ) );
191 }
192
193 $this->addOption( 'DISTINCT' );
194 } elseif ( isset( $params['prlevel'] ) ) {
195 $this->dieWithError(
196 [ 'apierror-invalidparammix-mustusewith', 'prlevel', 'prtype' ], 'invalidparammix'
197 );
198 }
199
200 if ( $params['filterlanglinks'] == 'withoutlanglinks' ) {
201 $this->addTables( 'langlinks' );
202 $this->addJoinConds( [ 'langlinks' => [ 'LEFT JOIN', 'page_id=ll_from' ] ] );
203 $this->addWhere( [ 'll_from' => null ] );
204 $forceNameTitleIndex = false;
205 } elseif ( $params['filterlanglinks'] == 'withlanglinks' ) {
206 $this->addTables( 'langlinks' );
207 $this->addWhere( 'page_id=ll_from' );
208 $this->addOption( 'STRAIGHT_JOIN' );
209
210 $dbType = $db->getType();
211 if ( $dbType === 'mysql' || $dbType === 'sqlite' ) {
212 // Avoid MySQL filesort reported in 2015 (T78276)
213 $this->addOption( 'GROUP BY', [ 'page_title' ] );
214 } else {
215 // SQL:1999 rules only counting primary keys
216 $this->addOption( 'GROUP BY', [ 'page_title', 'page_id' ] );
217 }
218
219 $forceNameTitleIndex = false;
220 }
221
222 if ( $forceNameTitleIndex ) {
223 $this->addOption( 'USE INDEX', 'page_name_title' );
224 }
225
226 $limit = $params['limit'];
227 $this->addOption( 'LIMIT', $limit + 1 );
228 $res = $this->select( __METHOD__ );
229
230 // Get gender information
231 if ( $this->namespaceInfo->hasGenderDistinction( $params['namespace'] ) ) {
232 $users = [];
233 foreach ( $res as $row ) {
234 $users[] = $row->page_title;
235 }
236 $this->genderCache->doQuery( $users, __METHOD__ );
237 $res->rewind(); // reset
238 }
239
240 $count = 0;
241 $result = $this->getResult();
242 foreach ( $res as $row ) {
243 if ( ++$count > $limit ) {
244 // We've reached the one extra which shows that there are
245 // additional pages to be had. Stop here...
246 $this->setContinueEnumParameter( 'continue', $row->page_title );
247 break;
248 }
249
250 if ( $miserModeFilterRedir && (int)$row->page_is_redirect !== $miserModeFilterRedirValue ) {
251 // Filter implemented in PHP due to being in Miser Mode
252 continue;
253 }
254
255 if ( $resultPageSet === null ) {
256 $title = Title::makeTitle( $row->page_namespace, $row->page_title );
257 $vals = [
258 'pageid' => (int)$row->page_id,
259 'ns' => $title->getNamespace(),
260 'title' => $title->getPrefixedText()
261 ];
262 $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $vals );
263 if ( !$fit ) {
264 $this->setContinueEnumParameter( 'continue', $row->page_title );
265 break;
266 }
267 } else {
268 $resultPageSet->processDbRow( $row );
269 }
270 }
271
272 if ( $resultPageSet === null ) {
273 $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'p' );
274 }
275 }
276
277 public function getAllowedParams() {
278 $ret = [
279 'from' => null,
280 'continue' => [
281 ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
282 ],
283 'to' => null,
284 'prefix' => null,
285 'namespace' => [
286 ParamValidator::PARAM_DEFAULT => NS_MAIN,
287 ParamValidator::PARAM_TYPE => 'namespace',
288 ],
289 'filterredir' => [
290 ParamValidator::PARAM_DEFAULT => 'all',
291 ParamValidator::PARAM_TYPE => [
292 'all',
293 'redirects',
294 'nonredirects'
295 ]
296 ],
297 'filterlanglinks' => [
298 ParamValidator::PARAM_TYPE => [
299 'withlanglinks',
300 'withoutlanglinks',
301 'all'
302 ],
303 ParamValidator::PARAM_DEFAULT => 'all'
304 ],
305 'minsize' => [
306 ParamValidator::PARAM_TYPE => 'integer',
307 ],
308 'maxsize' => [
309 ParamValidator::PARAM_TYPE => 'integer',
310 ],
311 'prtype' => [
312 ParamValidator::PARAM_TYPE => $this->restrictionStore->listAllRestrictionTypes( true ),
313 ParamValidator::PARAM_ISMULTI => true
314 ],
315 'prlevel' => [
316 ParamValidator::PARAM_TYPE =>
318 ParamValidator::PARAM_ISMULTI => true
319 ],
320 'prfiltercascade' => [
321 ParamValidator::PARAM_DEFAULT => 'all',
322 ParamValidator::PARAM_TYPE => [
323 'cascading',
324 'noncascading',
325 'all'
326 ],
327 ],
328 'prexpiry' => [
329 ParamValidator::PARAM_TYPE => [
330 'indefinite',
331 'definite',
332 'all'
333 ],
334 ParamValidator::PARAM_DEFAULT => 'all',
336 ],
337 'limit' => [
338 ParamValidator::PARAM_DEFAULT => 10,
339 ParamValidator::PARAM_TYPE => 'limit',
340 IntegerDef::PARAM_MIN => 1,
341 IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1,
342 IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2
343 ],
344 'dir' => [
345 ParamValidator::PARAM_DEFAULT => 'ascending',
346 ParamValidator::PARAM_TYPE => [
347 'ascending',
348 'descending'
349 ]
350 ],
351 ];
352
353 if ( $this->getConfig()->get( MainConfigNames::MiserMode ) ) {
354 $ret['filterredir'][ApiBase::PARAM_HELP_MSG_APPEND] = [ 'api-help-param-limited-in-miser-mode' ];
355 }
356
357 return $ret;
358 }
359
360 protected function getExamplesMessages() {
361 return [
362 'action=query&list=allpages&apfrom=B'
363 => 'apihelp-query+allpages-example-b',
364 'action=query&generator=allpages&gaplimit=4&gapfrom=T&prop=info'
365 => 'apihelp-query+allpages-example-generator',
366 'action=query&generator=allpages&gaplimit=2&' .
367 'gapfilterredir=nonredirects&gapfrom=Re&prop=revisions&rvprop=content'
368 => 'apihelp-query+allpages-example-generator-revisions',
369 ];
370 }
371
372 public function getHelpUrls() {
373 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Allpages';
374 }
375}
376
378class_alias( ApiQueryAllPages::class, 'ApiQueryAllPages' );
const NS_MAIN
Definition Defines.php:65
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1522
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:557
parseContinueParamOrDie(string $continue, array $types)
Parse the 'continue' parameter in the usual format and validate the types of each part,...
Definition ApiBase.php:1707
getResult()
Get the result object.
Definition ApiBase.php:696
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
Definition ApiBase.php:221
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
Definition ApiBase.php:189
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:181
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition ApiBase.php:248
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:837
const LIMIT_BIG1
Fast query, standard limit.
Definition ApiBase.php:246
Query module to enumerate all available pages.
getCacheMode( $params)
Get the cache mode for the data generated by this module.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
getExamplesMessages()
Returns usage examples for this module.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
getHelpUrls()
Return links to more detailed help pages about the module.
__construct(ApiQuery $query, string $moduleName, NamespaceInfo $namespaceInfo, GenderCache $genderCache, RestrictionStore $restrictionStore)
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.
addJoinConds( $join_conds)
Add a set of JOIN conditions 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.
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.
addWhereFld( $field, $value)
Equivalent to addWhere( [ $field => $value ] )
addFields( $value)
Add a set of fields to select to the internal array.
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.
setContinueEnumParameter( $paramName, $paramValue)
Overridden to set the generator param if in generator mode.
This is the main query class.
Definition ApiQuery.php:50
Look up "gender" user preference.
A class containing constants representing the names of configuration variables.
const RestrictionLevels
Name constant for the RestrictionLevels setting, for use with Config::get()
const MiserMode
Name constant for the MiserMode setting, for use with Config::get()
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
Represents a title within MediaWiki.
Definition Title.php:78
Service for formatting and validating API parameters.
Type definition for integer types.
Content of like value.
Definition LikeValue.php:14
array $params
The job parameters.