MediaWiki master
ApiQueryLogEvents.php
Go to the documentation of this file.
1<?php
9namespace MediaWiki\Api;
10
30use Wikimedia\Timestamp\TimestampFormat as TS;
31
38
39 private CommentStore $commentStore;
40 private CommentFormatter $commentFormatter;
41 private NameTableStore $changeTagDefStore;
42 private ChangeTagsStore $changeTagsStore;
43 private UserNameUtils $userNameUtils;
44 private LogFormatterFactory $logFormatterFactory;
45
47 private $formattedComments;
48
49 public function __construct(
50 ApiQuery $query,
51 string $moduleName,
52 CommentStore $commentStore,
53 RowCommentFormatter $commentFormatter,
54 NameTableStore $changeTagDefStore,
55 ChangeTagsStore $changeTagsStore,
56 UserNameUtils $userNameUtils,
57 LogFormatterFactory $logFormatterFactory
58 ) {
59 parent::__construct( $query, $moduleName, 'le' );
60 $this->commentStore = $commentStore;
61 $this->commentFormatter = $commentFormatter;
62 $this->changeTagDefStore = $changeTagDefStore;
63 $this->changeTagsStore = $changeTagsStore;
64 $this->userNameUtils = $userNameUtils;
65 $this->logFormatterFactory = $logFormatterFactory;
66 }
67
68 private bool $fld_ids = false;
69 private bool $fld_title = false;
70 private bool $fld_type = false;
71 private bool $fld_user = false;
72 private bool $fld_userid = false;
73 private bool $fld_timestamp = false;
74 private bool $fld_comment = false;
75 private bool $fld_parsedcomment = false;
76 private bool $fld_details = false;
77 private bool $fld_tags = false;
78
79 public function execute() {
80 $params = $this->extractRequestParams();
81 $db = $this->getDB();
82 $this->requireMaxOneParameter( $params, 'title', 'prefix', 'namespace' );
83
84 $prop = array_fill_keys( $params['prop'], true );
85
86 $this->fld_ids = isset( $prop['ids'] );
87 $this->fld_title = isset( $prop['title'] );
88 $this->fld_type = isset( $prop['type'] );
89 $this->fld_user = isset( $prop['user'] );
90 $this->fld_userid = isset( $prop['userid'] );
91 $this->fld_timestamp = isset( $prop['timestamp'] );
92 $this->fld_comment = isset( $prop['comment'] );
93 $this->fld_parsedcomment = isset( $prop['parsedcomment'] );
94 $this->fld_details = isset( $prop['details'] );
95 $this->fld_tags = isset( $prop['tags'] );
96
97 $hideLogs = LogEventsList::getExcludeClause( $db, 'user', $this->getAuthority() );
98 if ( $hideLogs !== false ) {
99 $this->addWhere( $hideLogs );
100 }
101
102 $this->addTables( 'logging' );
103
104 $this->addFields( [
105 'log_id',
106 'log_type',
107 'log_action',
108 'log_timestamp',
109 'log_deleted',
110 ] );
111
112 if ( $params['ids'] ) {
113 $this->addWhereIDsFld( 'logging', 'log_id', $params['ids'] );
114 }
115
116 $user = $params['user'];
117 if ( $this->fld_user || $this->fld_userid || $user !== null ) {
118 $this->addTables( 'actor' );
119 $this->addJoinConds( [
120 'actor' => [ 'JOIN', 'actor_id=log_actor' ],
121 ] );
122 $this->addFieldsIf( [ 'actor_name', 'actor_user' ], $this->fld_user );
123 $this->addFieldsIf( 'actor_user', $this->fld_userid );
124 if ( $user !== null ) {
125 $this->addWhereFld( 'actor_name', $user );
126 }
127 }
128
129 if ( $this->fld_ids ) {
130 $this->addTables( 'page' );
131 $this->addJoinConds( [
132 'page' => [ 'LEFT JOIN',
133 [ 'log_namespace=page_namespace',
134 'log_title=page_title' ] ]
135 ] );
136 // log_page is the page_id saved at log time, whereas page_id is from a
137 // join at query time. This leads to different results in various
138 // scenarios, e.g. deletion, recreation.
139 $this->addFields( [ 'page_id', 'log_page' ] );
140 }
141 $this->addFieldsIf(
142 [ 'log_namespace', 'log_title' ],
143 $this->fld_title || $this->fld_parsedcomment
144 );
145 $this->addFieldsIf( 'log_params', $this->fld_details || $this->fld_ids );
146
147 if ( $this->fld_comment || $this->fld_parsedcomment ) {
148 $commentQuery = $this->commentStore->getJoin( 'log_comment' );
149 $this->addTables( $commentQuery['tables'] );
150 $this->addFields( $commentQuery['fields'] );
151 $this->addJoinConds( $commentQuery['joins'] );
152 }
153
154 if ( $this->fld_tags ) {
155 $this->addFields( [
156 'ts_tags' => $this->changeTagsStore->makeTagSummarySubquery( 'logging' )
157 ] );
158 }
159
160 if ( $params['tag'] !== null ) {
161 $this->addTables( 'change_tag' );
162 $this->addJoinConds( [ 'change_tag' => [ 'JOIN',
163 [ 'log_id=ct_log_id' ] ] ] );
164 try {
165 $this->addWhereFld( 'ct_tag_id', $this->changeTagDefStore->getId( $params['tag'] ) );
166 } catch ( NameTableAccessException ) {
167 // Return nothing.
168 $this->addWhere( '1=0' );
169 }
170 }
171
172 if ( $params['action'] !== null ) {
173 // Do validation of action param, list of allowed actions can contains wildcards
174 // Allow the param, when the actions is in the list or a wildcard version is listed.
175 $logAction = $params['action'];
176 if ( !str_contains( $logAction, '/' ) ) {
177 // all items in the list have a slash
178 $valid = false;
179 } else {
180 $logActions = array_fill_keys( $this->getAllowedLogActions(), true );
181 [ $type, $action ] = explode( '/', $logAction, 2 );
182 $valid = isset( $logActions[$logAction] ) || isset( $logActions[$type . '/*'] );
183 }
184
185 if ( !$valid ) {
186 $encParamName = $this->encodeParamName( 'action' );
187 $this->dieWithError(
188 [ 'apierror-unrecognizedvalue', $encParamName, wfEscapeWikiText( $logAction ) ],
189 "unknown_$encParamName"
190 );
191 }
192
193 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable,PhanPossiblyUndeclaredVariable T240141
194 $this->addWhereFld( 'log_type', $type );
195 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable,PhanPossiblyUndeclaredVariable T240141
196 $this->addWhereFld( 'log_action', $action );
197 } elseif ( $params['type'] !== null ) {
198 $this->addWhereFld( 'log_type', $params['type'] );
199 }
200
202 'log_timestamp',
203 $params['dir'],
204 $params['start'],
205 $params['end']
206 );
207 // Include in ORDER BY for uniqueness
208 $this->addWhereRange( 'log_id', $params['dir'], null, null );
209
210 if ( $params['continue'] !== null ) {
211 $cont = $this->parseContinueParamOrDie( $params['continue'], [ 'timestamp', 'int' ] );
212 $op = ( $params['dir'] === 'newer' ? '>=' : '<=' );
213 $this->addWhere( $db->buildComparison( $op, [
214 'log_timestamp' => $db->timestamp( $cont[0] ),
215 'log_id' => $cont[1],
216 ] ) );
217 }
218
219 $limit = $params['limit'];
220 $this->addOption( 'LIMIT', $limit + 1 );
221
222 $title = $params['title'];
223 if ( $title !== null ) {
224 $titleObj = Title::newFromText( $title );
225 if ( $titleObj === null || $titleObj->isExternal() ) {
226 $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $title ) ] );
227 }
228 $this->addWhereFld( 'log_namespace', $titleObj->getNamespace() );
229 $this->addWhereFld( 'log_title', $titleObj->getDBkey() );
230 }
231
232 if ( $params['namespace'] !== null ) {
233 $this->addWhereFld( 'log_namespace', $params['namespace'] );
234 }
235
236 $prefix = $params['prefix'];
237
238 if ( $prefix !== null ) {
239 if ( $this->getConfig()->get( MainConfigNames::MiserMode ) ) {
240 $this->dieWithError( 'apierror-prefixsearchdisabled' );
241 }
242
243 $title = Title::newFromText( $prefix );
244 if ( $title === null || $title->isExternal() ) {
245 $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $prefix ) ] );
246 }
247 $this->addWhereFld( 'log_namespace', $title->getNamespace() );
248 $this->addWhere(
249 $db->expr( 'log_title', IExpression::LIKE, new LikeValue( $title->getDBkey(), $db->anyString() ) )
250 );
251 }
252
253 // Paranoia: avoid brute force searches (T19342)
254 if ( $params['namespace'] !== null || $title !== null || $user !== null ) {
255 if ( !$this->getAuthority()->isAllowed( 'deletedhistory' ) ) {
256 $titleBits = LogPage::DELETED_ACTION;
257 $userBits = LogPage::DELETED_USER;
258 } elseif ( !$this->getAuthority()->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
259 $titleBits = LogPage::DELETED_ACTION | LogPage::DELETED_RESTRICTED;
260 $userBits = LogPage::DELETED_USER | LogPage::DELETED_RESTRICTED;
261 } else {
262 $titleBits = 0;
263 $userBits = 0;
264 }
265 if ( ( $params['namespace'] !== null || $title !== null ) && $titleBits ) {
266 $this->addWhere( $db->bitAnd( 'log_deleted', $titleBits ) . " != $titleBits" );
267 }
268 if ( $user !== null && $userBits ) {
269 $this->addWhere( $db->bitAnd( 'log_deleted', $userBits ) . " != $userBits" );
270 }
271 }
272
273 // T220999: MySQL/MariaDB (10.1.37) can sometimes irrationally decide that querying `actor` before
274 // `logging` and filesorting is somehow better than querying $limit+1 rows from `logging`.
275 // Tell it not to reorder the query. But not when `letag` was used, as it seems as likely
276 // to be harmed as helped in that case.
277 // If "user" was specified, it's obviously correct to query actor first (T282122)
278 if ( $params['tag'] === null && $user === null ) {
279 $this->addOption( 'STRAIGHT_JOIN' );
280 }
281
282 $this->addOption(
283 'MAX_EXECUTION_TIME',
285 );
286
287 $count = 0;
288 $res = $this->select( __METHOD__ );
289
290 if ( $this->fld_title ) {
291 $this->executeGenderCacheFromResultWrapper( $res, __METHOD__, 'log' );
292 }
293 if ( $this->fld_parsedcomment ) {
294 $this->formattedComments = $this->commentFormatter->formatItems(
295 $this->commentFormatter->rows( $res )
296 ->commentKey( 'log_comment' )
297 ->indexField( 'log_id' )
298 ->namespaceField( 'log_namespace' )
299 ->titleField( 'log_title' )
300 );
301 }
302
303 $result = $this->getResult();
304 foreach ( $res as $row ) {
305 if ( ++$count > $limit ) {
306 // We've reached the one extra which shows that there are
307 // additional pages to be had. Stop here...
308 $this->setContinueEnumParameter( 'continue', "$row->log_timestamp|$row->log_id" );
309 break;
310 }
311
312 $vals = $this->extractRowInfo( $row );
313 $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $vals );
314 if ( !$fit ) {
315 $this->setContinueEnumParameter( 'continue', "$row->log_timestamp|$row->log_id" );
316 break;
317 }
318 }
319 $result->addIndexedTagName( [ 'query', $this->getModuleName() ], 'item' );
320 }
321
322 private function extractRowInfo( \stdClass $row ): array {
323 $logEntry = DatabaseLogEntry::newFromRow( $row );
324 $vals = [
325 ApiResult::META_TYPE => 'assoc',
326 ];
327 $anyHidden = false;
328
329 if ( $this->fld_ids ) {
330 $vals['logid'] = (int)$row->log_id;
331 }
332
333 if ( $this->fld_title ) {
334 $title = Title::makeTitle( $row->log_namespace, $row->log_title );
335 }
336
337 $authority = $this->getAuthority();
338 if ( $this->fld_title || $this->fld_ids || ( $this->fld_details && $row->log_params !== '' ) ) {
339 if ( LogEventsList::isDeleted( $row, LogPage::DELETED_ACTION ) ) {
340 $vals['actionhidden'] = true;
341 $anyHidden = true;
342 }
343 if ( LogEventsList::userCan( $row, LogPage::DELETED_ACTION, $authority ) ) {
344 if ( $this->fld_title ) {
345 // @phan-suppress-next-next-line PhanTypeMismatchArgumentNullable,PhanPossiblyUndeclaredVariable
346 // title is set when used
347 ApiQueryBase::addTitleInfo( $vals, $title );
348 }
349 if ( $this->fld_ids ) {
350 $vals['pageid'] = (int)$row->page_id;
351 $vals['logpage'] = (int)$row->log_page;
352 $revId = $logEntry->getAssociatedRevId();
353 if ( $revId ) {
354 $vals['revid'] = (int)$revId;
355 }
356 }
357 if ( $this->fld_details ) {
358 $vals['params'] = $this->logFormatterFactory->newFromEntry( $logEntry )->formatParametersForApi();
359 }
360 }
361 }
362
363 if ( $this->fld_type ) {
364 $vals['type'] = $row->log_type;
365 $vals['action'] = $row->log_action;
366 }
367
368 if ( $this->fld_user || $this->fld_userid ) {
369 if ( LogEventsList::isDeleted( $row, LogPage::DELETED_USER ) ) {
370 $vals['userhidden'] = true;
371 $anyHidden = true;
372 }
373 if ( LogEventsList::userCan( $row, LogPage::DELETED_USER, $authority ) ) {
374 if ( $this->fld_user ) {
375 $vals['user'] = $row->actor_name;
376 }
377 if ( $this->fld_userid ) {
378 $vals['userid'] = (int)$row->actor_user;
379 }
380
381 if ( isset( $vals['user'] ) && $this->userNameUtils->isTemp( $vals['user'] ) ) {
382 $vals['temp'] = true;
383 }
384
385 if ( !$row->actor_user ) {
386 $vals['anon'] = true;
387 }
388 }
389 }
390 if ( $this->fld_timestamp ) {
391 $vals['timestamp'] = wfTimestamp( TS::ISO_8601, $row->log_timestamp );
392 }
393
394 if ( $this->fld_comment || $this->fld_parsedcomment ) {
395 if ( LogEventsList::isDeleted( $row, LogPage::DELETED_COMMENT ) ) {
396 $vals['commenthidden'] = true;
397 $anyHidden = true;
398 }
399 if ( LogEventsList::userCan( $row, LogPage::DELETED_COMMENT, $authority ) ) {
400 if ( $this->fld_comment ) {
401 $vals['comment'] = $this->commentStore->getComment( 'log_comment', $row )->text;
402 }
403
404 if ( $this->fld_parsedcomment ) {
405 // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
406 $vals['parsedcomment'] = $this->formattedComments[$row->log_id];
407 }
408 }
409 }
410
411 if ( $this->fld_tags ) {
412 if ( $row->ts_tags ) {
413 $tags = explode( ',', $row->ts_tags );
414 ApiResult::setIndexedTagName( $tags, 'tag' );
415 $vals['tags'] = $tags;
416 } else {
417 $vals['tags'] = [];
418 }
419 }
420
421 if ( $anyHidden && LogEventsList::isDeleted( $row, LogPage::DELETED_RESTRICTED ) ) {
422 $vals['suppressed'] = true;
423 }
424
425 return $vals;
426 }
427
431 private function getAllowedLogActions() {
432 $config = $this->getConfig();
433 return array_keys( array_merge(
434 $config->get( MainConfigNames::LogActions ),
436 ) );
437 }
438
440 public function getCacheMode( $params ) {
441 if ( $this->userCanSeeRevDel() ) {
442 return 'private';
443 }
444 if ( $params['prop'] !== null && in_array( 'parsedcomment', $params['prop'] ) ) {
445 // MediaWiki\CommentFormatter\CommentFormatter::formatItems() calls wfMessage() among other things
446 return 'anon-public-user-private';
447 } elseif ( LogEventsList::getExcludeClause( $this->getDB(), 'user', $this->getAuthority() )
448 === LogEventsList::getExcludeClause( $this->getDB(), 'public' )
449 ) { // Output can only contain public data.
450 return 'public';
451 } else {
452 return 'anon-public-user-private';
453 }
454 }
455
457 public function getAllowedParams( $flags = 0 ) {
458 $config = $this->getConfig();
459 if ( $flags & ApiBase::GET_VALUES_FOR_HELP ) {
460 $logActions = $this->getAllowedLogActions();
461 sort( $logActions );
462 } else {
463 $logActions = null;
464 }
465 $ret = [
466 'prop' => [
467 ParamValidator::PARAM_ISMULTI => true,
468 ParamValidator::PARAM_DEFAULT => 'ids|title|type|user|timestamp|comment|details',
469 ParamValidator::PARAM_TYPE => [
470 'ids',
471 'title',
472 'type',
473 'user',
474 'userid',
475 'timestamp',
476 'comment',
477 'parsedcomment',
478 'details',
479 'tags'
480 ],
482 ],
483 'type' => [
484 ParamValidator::PARAM_TYPE => LogPage::validTypes(),
485 ],
486 'action' => [
487 // validation on request is done in execute()
488 ParamValidator::PARAM_TYPE => $logActions
489 ],
490 'start' => [
491 ParamValidator::PARAM_TYPE => 'timestamp'
492 ],
493 'end' => [
494 ParamValidator::PARAM_TYPE => 'timestamp'
495 ],
496 'dir' => [
497 ParamValidator::PARAM_DEFAULT => 'older',
498 ParamValidator::PARAM_TYPE => [
499 'newer',
500 'older'
501 ],
502 ApiBase::PARAM_HELP_MSG => 'api-help-param-direction',
504 'newer' => 'api-help-paramvalue-direction-newer',
505 'older' => 'api-help-paramvalue-direction-older',
506 ],
507 ],
508 'ids' => [
509 ParamValidator::PARAM_TYPE => 'integer',
510 ParamValidator::PARAM_ISMULTI => true
511 ],
512 'user' => [
513 ParamValidator::PARAM_TYPE => 'user',
514 UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name', 'ip', 'temp', 'id', 'interwiki' ],
515 ],
516 'title' => null,
517 'namespace' => [
518 ParamValidator::PARAM_TYPE => 'namespace',
519 NamespaceDef::PARAM_EXTRA_NAMESPACES => [ NS_MEDIA, NS_SPECIAL ],
520 ],
521 'prefix' => [],
522 'tag' => null,
523 'limit' => [
524 ParamValidator::PARAM_DEFAULT => 10,
525 ParamValidator::PARAM_TYPE => 'limit',
526 IntegerDef::PARAM_MIN => 1,
527 IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1,
528 IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2
529 ],
530 'continue' => [
531 ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
532 ],
533 ];
534
535 if ( $config->get( MainConfigNames::MiserMode ) ) {
536 $ret['prefix'][ApiBase::PARAM_HELP_MSG] = 'api-help-param-disabled-in-miser-mode';
537 }
538
539 return $ret;
540 }
541
543 protected function getExamplesMessages() {
544 return [
545 'action=query&list=logevents'
546 => 'apihelp-query+logevents-example-simple',
547 ];
548 }
549
551 public function getHelpUrls() {
552 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Logevents';
553 }
554}
555
557class_alias( ApiQueryLogEvents::class, 'ApiQueryLogEvents' );
const NS_SPECIAL
Definition Defines.php:40
const NS_MEDIA
Definition Defines.php:39
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
wfTimestamp( $outputtype=TS::UNIX, $ts=0)
Get a timestamp string in one of various formats.
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1511
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:543
parseContinueParamOrDie(string $continue, array $types)
Parse the 'continue' parameter in the usual format and validate the types of each part,...
Definition ApiBase.php:1696
getResult()
Get the result object.
Definition ApiBase.php:682
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
Definition ApiBase.php:207
requireMaxOneParameter( $params,... $required)
Dies if more than one parameter from a certain set of parameters are set and not false.
Definition ApiBase.php:998
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:167
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition ApiBase.php:234
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition ApiBase.php:801
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:823
const GET_VALUES_FOR_HELP
getAllowedParams() flag: When this is set, the result could take longer to generate,...
Definition ApiBase.php:245
const LIMIT_BIG1
Fast query, standard limit.
Definition ApiBase.php:232
This is a base class for all Query modules.
addOption( $name, $value=null)
Add an option such as LIMIT or USE INDEX.
addFieldsIf( $value, $condition)
Same as addFields(), but add the fields only if a condition is met.
static addTitleInfo(&$arr, $title, $prefix='')
Add information (title and namespace) about a Title object to a result array.
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.
addWhereIDsFld( $table, $field, $ids)
Like addWhereFld for an integer list of IDs.
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.
addWhere( $value)
Add a set of WHERE clauses to the internal array.
executeGenderCacheFromResultWrapper(IResultWrapper $res, $fname=__METHOD__, $fieldPrefix='page')
Preprocess the result set to fill the GenderCache with the necessary information before using self::a...
addTimestampWhereRange( $field, $dir, $start, $end, $sort=true)
Add a WHERE clause corresponding to a range, similar to addWhereRange, but converts $start and $end t...
setContinueEnumParameter( $paramName, $paramValue)
Set a query-continue value.
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.
Query action to List the log events, with optional filtering by various parameters.
getHelpUrls()
Return links to more detailed help pages about the module.1.25, returning boolean false is deprecated...
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
getExamplesMessages()
Returns usage examples for this module.Return value has query strings as keys, with values being eith...
__construct(ApiQuery $query, string $moduleName, CommentStore $commentStore, RowCommentFormatter $commentFormatter, NameTableStore $changeTagDefStore, ChangeTagsStore $changeTagsStore, UserNameUtils $userNameUtils, LogFormatterFactory $logFormatterFactory)
getCacheMode( $params)
Get the cache mode for the data generated by this module.Override this in the module subclass....
This is the main query class.
Definition ApiQuery.php:36
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
const META_TYPE
Key for the 'type' metadata item.
Read-write access to the change_tags table.
This is the main service interface for converting single-line comments from various DB comment fields...
This is basically a CommentFormatter with a CommentStore dependency, allowing it to retrieve comment ...
Handle database storage of comments such as edit summaries and log reasons.
makeTitle( $linkId)
Convert a link ID to a Title.to override Title
A value class to process existing log entries.
Class to simplify the use of log pages.
Definition LogPage.php:35
A class containing constants representing the names of configuration variables.
const MaxExecutionTimeForExpensiveQueries
Name constant for the MaxExecutionTimeForExpensiveQueries setting, for use with Config::get()
const LogActionsHandlers
Name constant for the LogActionsHandlers setting, for use with Config::get()
const LogActions
Name constant for the LogActions setting, for use with Config::get()
const MiserMode
Name constant for the MiserMode setting, for use with Config::get()
Type definition for namespace types.
Type definition for user types.
Definition UserDef.php:27
Exception representing a failure to look up a row from a name table.
Represents a title within MediaWiki.
Definition Title.php:69
UserNameUtils service.
Service for formatting and validating API parameters.
Type definition for integer types.
Content of like value.
Definition LikeValue.php:14