MediaWiki REL1_37
ApiQueryAllLinks.php
Go to the documentation of this file.
1<?php
29
31 private $fieldTitle = 'title';
33 private $hasNamespace = true;
34 private $useIndex = null;
35 private $props = [];
36
39
41 private $genderCache;
42
49 public function __construct(
50 ApiQuery $query,
51 $moduleName,
54 ) {
55 switch ( $moduleName ) {
56 case 'alllinks':
57 $prefix = 'al';
58 $this->table = 'pagelinks';
59 $this->tablePrefix = 'pl_';
60 $this->useIndex = 'pl_namespace';
61 $this->indexTag = 'l';
62 break;
63 case 'alltransclusions':
64 $prefix = 'at';
65 $this->table = 'templatelinks';
66 $this->tablePrefix = 'tl_';
67 $this->dfltNamespace = NS_TEMPLATE;
68 $this->useIndex = 'tl_namespace';
69 $this->indexTag = 't';
70 break;
71 case 'allfileusages':
72 $prefix = 'af';
73 $this->table = 'imagelinks';
74 $this->tablePrefix = 'il_';
75 $this->fieldTitle = 'to';
76 $this->dfltNamespace = NS_FILE;
77 $this->hasNamespace = false;
78 $this->indexTag = 'f';
79 break;
80 case 'allredirects':
81 $prefix = 'ar';
82 $this->table = 'redirect';
83 $this->tablePrefix = 'rd_';
84 $this->indexTag = 'r';
85 $this->props = [
86 'fragment' => 'rd_fragment',
87 'interwiki' => 'rd_interwiki',
88 ];
89 break;
90 default:
91 ApiBase::dieDebug( __METHOD__, 'Unknown module name' );
92 }
93
94 parent::__construct( $query, $moduleName, $prefix );
95 $this->namespaceInfo = $namespaceInfo;
96 $this->genderCache = $genderCache;
97 }
98
99 public function execute() {
100 $this->run();
101 }
102
103 public function getCacheMode( $params ) {
104 return 'public';
105 }
106
107 public function executeGenerator( $resultPageSet ) {
108 $this->run( $resultPageSet );
109 }
110
115 private function run( $resultPageSet = null ) {
116 $db = $this->getDB();
117 $params = $this->extractRequestParams();
118
119 $pfx = $this->tablePrefix;
121 $prop = array_fill_keys( $params['prop'], true );
122 $fld_ids = isset( $prop['ids'] );
123 $fld_title = isset( $prop['title'] );
124 if ( $this->hasNamespace ) {
125 $namespace = $params['namespace'];
126 } else {
127 $namespace = $this->dfltNamespace;
128 }
129
130 if ( $params['unique'] ) {
131 $matches = array_intersect_key( $prop, $this->props + [ 'ids' => 1 ] );
132 if ( $matches ) {
133 $p = $this->getModulePrefix();
134 $this->dieWithError(
135 [
136 'apierror-invalidparammix-cannotusewith',
137 "{$p}prop=" . implode( '|', array_keys( $matches ) ),
138 "{$p}unique"
139 ],
140 'invalidparammix'
141 );
142 }
143 $this->addOption( 'DISTINCT' );
144 }
145
146 $this->addTables( $this->table );
147 if ( $this->hasNamespace ) {
148 $this->addWhereFld( $pfx . 'namespace', $namespace );
149 }
150
151 $continue = $params['continue'] !== null;
152 if ( $continue ) {
153 $continueArr = explode( '|', $params['continue'] );
154 $op = $params['dir'] == 'descending' ? '<' : '>';
155 if ( $params['unique'] ) {
156 $this->dieContinueUsageIf( count( $continueArr ) != 1 );
157 $continueTitle = $db->addQuotes( $continueArr[0] );
158 $this->addWhere( "{$pfx}{$fieldTitle} $op= $continueTitle" );
159 } else {
160 $this->dieContinueUsageIf( count( $continueArr ) != 2 );
161 $continueTitle = $db->addQuotes( $continueArr[0] );
162 $continueFrom = (int)$continueArr[1];
163 $this->addWhere(
164 "{$pfx}{$fieldTitle} $op $continueTitle OR " .
165 "({$pfx}{$fieldTitle} = $continueTitle AND " .
166 "{$pfx}from $op= $continueFrom)"
167 );
168 }
169 }
170
171 // 'continue' always overrides 'from'
172 $from = $continue || $params['from'] === null ? null :
173 $this->titlePartToKey( $params['from'], $namespace );
174 $to = $params['to'] === null ? null :
175 $this->titlePartToKey( $params['to'], $namespace );
176 $this->addWhereRange( $pfx . $fieldTitle, 'newer', $from, $to );
177
178 if ( isset( $params['prefix'] ) ) {
179 $this->addWhere( $pfx . $fieldTitle . $db->buildLike( $this->titlePartToKey(
180 $params['prefix'], $namespace ), $db->anyString() ) );
181 }
182
183 $this->addFields( [ 'pl_title' => $pfx . $fieldTitle ] );
184 $this->addFieldsIf( [ 'pl_from' => $pfx . 'from' ], !$params['unique'] );
185 foreach ( $this->props as $name => $field ) {
186 $this->addFieldsIf( $field, isset( $prop[$name] ) );
187 }
188
189 if ( $this->useIndex ) {
190 $this->addOption( 'USE INDEX', $this->useIndex );
191 }
192 $limit = $params['limit'];
193 $this->addOption( 'LIMIT', $limit + 1 );
194
195 $sort = ( $params['dir'] == 'descending' ? ' DESC' : '' );
196 $orderBy = [];
197 $orderBy[] = $pfx . $fieldTitle . $sort;
198 if ( !$params['unique'] ) {
199 $orderBy[] = $pfx . 'from' . $sort;
200 }
201 $this->addOption( 'ORDER BY', $orderBy );
202
203 $res = $this->select( __METHOD__ );
204
205 // Get gender information
206 if ( $res->numRows() && $resultPageSet === null ) {
207 if ( $this->namespaceInfo->hasGenderDistinction( $namespace ) ) {
208 $users = [];
209 foreach ( $res as $row ) {
210 $users[] = $row->pl_title;
211 }
212 if ( $users !== [] ) {
213 $this->genderCache->doQuery( $users, __METHOD__ );
214 }
215 }
216 }
217
218 $pageids = [];
219 $titles = [];
220 $count = 0;
221 $result = $this->getResult();
222 foreach ( $res as $row ) {
223 if ( ++$count > $limit ) {
224 // We've reached the one extra which shows that there are
225 // additional pages to be had. Stop here...
226 if ( $params['unique'] ) {
227 $this->setContinueEnumParameter( 'continue', $row->pl_title );
228 } else {
229 $this->setContinueEnumParameter( 'continue', $row->pl_title . '|' . $row->pl_from );
230 }
231 break;
232 }
233
234 if ( $resultPageSet === null ) {
235 $vals = [
236 ApiResult::META_TYPE => 'assoc',
237 ];
238 if ( $fld_ids ) {
239 $vals['fromid'] = (int)$row->pl_from;
240 }
241 if ( $fld_title ) {
242 $title = Title::makeTitle( $namespace, $row->pl_title );
244 }
245 foreach ( $this->props as $name => $field ) {
246 if ( isset( $prop[$name] ) && $row->$field !== null && $row->$field !== '' ) {
247 $vals[$name] = $row->$field;
248 }
249 }
250 $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $vals );
251 if ( !$fit ) {
252 if ( $params['unique'] ) {
253 $this->setContinueEnumParameter( 'continue', $row->pl_title );
254 } else {
255 $this->setContinueEnumParameter( 'continue', $row->pl_title . '|' . $row->pl_from );
256 }
257 break;
258 }
259 } elseif ( $params['unique'] ) {
260 $titles[] = Title::makeTitle( $namespace, $row->pl_title );
261 } else {
262 $pageids[] = $row->pl_from;
263 }
264 }
265
266 if ( $resultPageSet === null ) {
267 $result->addIndexedTagName( [ 'query', $this->getModuleName() ], $this->indexTag );
268 } elseif ( $params['unique'] ) {
269 $resultPageSet->populateFromTitles( $titles );
270 } else {
271 $resultPageSet->populateFromPageIDs( $pageids );
272 }
273 }
274
275 public function getAllowedParams() {
276 $allowedParams = [
277 'continue' => [
278 ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
279 ],
280 'from' => null,
281 'to' => null,
282 'prefix' => null,
283 'unique' => false,
284 'prop' => [
286 ApiBase::PARAM_DFLT => 'title',
287 ApiBase::PARAM_TYPE => array_merge(
288 [ 'ids', 'title' ], array_keys( $this->props )
289 ),
291 ],
292 'namespace' => [
294 ApiBase::PARAM_TYPE => 'namespace',
296 ],
297 'limit' => [
299 ApiBase::PARAM_TYPE => 'limit',
303 ],
304 'dir' => [
305 ApiBase::PARAM_DFLT => 'ascending',
307 'ascending',
308 'descending'
309 ]
310 ],
311 ];
312 if ( !$this->hasNamespace ) {
313 unset( $allowedParams['namespace'] );
314 }
315
316 return $allowedParams;
317 }
318
319 protected function getExamplesMessages() {
320 $p = $this->getModulePrefix();
321 $name = $this->getModuleName();
322 $path = $this->getModulePath();
323
324 return [
325 "action=query&list={$name}&{$p}from=B&{$p}prop=ids|title"
326 => "apihelp-$path-example-b",
327 "action=query&list={$name}&{$p}unique=&{$p}from=B"
328 => "apihelp-$path-example-unique",
329 "action=query&generator={$name}&g{$p}unique=&g{$p}from=B"
330 => "apihelp-$path-example-unique-generator",
331 "action=query&generator={$name}&g{$p}from=B"
332 => "apihelp-$path-example-generator",
333 ];
334 }
335
336 public function getHelpUrls() {
337 $name = ucfirst( $this->getModuleName() );
338
339 return "https://www.mediawiki.org/wiki/Special:MyLanguage/API:{$name}";
340 }
341}
const NS_FILE
Definition Defines.php:70
const NS_MAIN
Definition Defines.php:64
const NS_TEMPLATE
Definition Defines.php:74
const NS_SPECIAL
Definition Defines.php:53
const NS_MEDIA
Definition Defines.php:52
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1436
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition ApiBase.php:505
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
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition ApiBase.php:1633
const PARAM_TYPE
Definition ApiBase.php:81
const PARAM_DFLT
Definition ApiBase.php:73
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
Definition ApiBase.php:195
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
getModulePath()
Get the path to this module.
Definition ApiBase.php:572
const PARAM_EXTRA_NAMESPACES
Definition ApiBase.php:121
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
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result 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.
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.
addFieldsIf( $value, $condition)
Same as addFields(), but add the fields only if a condition is met.
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...