111 private const MAX_DELETE_USES = 5000;
116 private const CHANGE_TAG =
'change_tag';
121 private const CHANGE_TAG_DEF =
'change_tag_def';
146 return MediaWikiServices::getInstance()->getChangeTagsStore()->getSoftwareTags( $all );
163 if ( $tags ===
'' || $tags ===
null ) {
172 $tags = explode(
',', $tags );
173 $order = array_flip( self::listDefinedTags() );
174 usort( $tags,
static function ( $a, $b ) use ( $order ) {
175 return ( $order[ $a ] ?? INF ) <=> ( $order[ $b ] ?? INF );
179 foreach ( $tags as $tag ) {
185 if ( $description ===
false ) {
190 [
'class' =>
'mw-tag-marker ' .
196 if ( !$displayTags ) {
197 return [
'', $classes ];
200 $markers = $localizer->msg(
'tag-list-wrapper' )
201 ->numParams( count( $displayTags ) )
202 ->rawParams( implode(
' ', $displayTags ) )
204 $markers =
Xml::tags(
'span', [
'class' =>
'mw-tag-markers' ], $markers );
206 return [ $markers, $classes ];
223 $msg = $context->
msg(
"tag-$tag" );
224 if ( !$msg->exists() ) {
230 if ( $msg->isDisabled() ) {
254 return $msg ? $msg->parse() :
false;
270 $msg = $context->
msg(
"tag-$tag-description" );
271 if ( !$msg->exists() ) {
274 if ( $msg->isDisabled() ) {
296 public static function addTags( $tags, $rc_id =
null, $rev_id =
null,
299 $result =
self::updateTags( $tags,
null, $rc_id, $rev_id, $log_id, $params, $rc );
300 return (
bool)$result[0];
332 public static function updateTags( $tagsToAdd, $tagsToRemove, &$rc_id =
null,
333 &$rev_id =
null, &$log_id =
null, $params =
null,
RecentChange $rc =
null,
336 $tagsToAdd = array_filter(
338 static function ( $value ) {
339 return ( $value ??
'' ) !==
'';
342 $tagsToRemove = array_filter(
343 (array)$tagsToRemove,
344 static function ( $value ) {
345 return ( $value ??
'' ) !==
'';
349 if ( !$rc_id && !$rev_id && !$log_id ) {
350 throw new BadMethodCallException(
'At least one of: RCID, revision ID, and log ID MUST be ' .
351 'specified when adding or removing a tag from a change!' );
354 $dbw = MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->getPrimaryDatabase();
362 $rc_id = $dbw->newSelectQueryBuilder()
365 ->join(
'recentchanges',
null, [
366 'rc_timestamp = log_timestamp',
369 ->where( [
'log_id' => $log_id ] )
370 ->caller( __METHOD__ )
372 } elseif ( $rev_id ) {
373 $rc_id = $dbw->newSelectQueryBuilder()
376 ->join(
'recentchanges',
null, [
377 'rc_this_oldid = rev_id'
379 ->where( [
'rev_id' => $rev_id ] )
380 ->caller( __METHOD__ )
383 } elseif ( !$log_id && !$rev_id ) {
385 $log_id = $dbw->newSelectQueryBuilder()
386 ->select(
'rc_logid' )
387 ->from(
'recentchanges' )
388 ->where( [
'rc_id' => $rc_id ] )
389 ->caller( __METHOD__ )
391 $rev_id = $dbw->newSelectQueryBuilder()
392 ->select(
'rc_this_oldid' )
393 ->from(
'recentchanges' )
394 ->where( [
'rc_id' => $rc_id ] )
395 ->caller( __METHOD__ )
399 if ( $log_id && !$rev_id ) {
400 $rev_id = $dbw->newSelectQueryBuilder()
401 ->select(
'ls_value' )
402 ->from(
'log_search' )
403 ->where( [
'ls_field' =>
'associated_rev_id',
'ls_log_id' => $log_id ] )
404 ->caller( __METHOD__ )
406 } elseif ( !$log_id && $rev_id ) {
407 $log_id = $dbw->newSelectQueryBuilder()
408 ->select(
'ls_log_id' )
409 ->from(
'log_search' )
410 ->where( [
'ls_field' =>
'associated_rev_id',
'ls_value' => (
string)$rev_id ] )
411 ->caller( __METHOD__ )
418 $tagsToAdd = array_values( array_diff( $tagsToAdd, $prevTags ) );
419 $newTags = array_unique( array_merge( $prevTags, $tagsToAdd ) );
422 $tagsToRemove = array_values( array_intersect( $tagsToRemove, $newTags ) );
423 $newTags = array_values( array_diff( $newTags, $tagsToRemove ) );
427 if ( $prevTags == $newTags ) {
428 return [ [], [], $prevTags ];
432 $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore();
433 if ( count( $tagsToAdd ) ) {
434 $changeTagMapping = [];
435 foreach ( $tagsToAdd as $tag ) {
436 $changeTagMapping[$tag] = $changeTagDefStore->acquireId( $tag );
440 $dbw->onTransactionPreCommitOrIdle(
static function () use ( $dbw, $tagsToAdd, $fname ) {
442 self::CHANGE_TAG_DEF,
443 [
'ctd_count = ctd_count + 1' ],
444 [
'ctd_name' => $tagsToAdd ],
450 foreach ( $tagsToAdd as $tag ) {
455 $tagsRows[] = array_filter(
457 'ct_rc_id' => $rc_id,
458 'ct_log_id' => $log_id,
459 'ct_rev_id' => $rev_id,
460 'ct_params' => $params,
461 'ct_tag_id' => $changeTagMapping[$tag] ??
null,
467 $dbw->insert( self::CHANGE_TAG, $tagsRows, __METHOD__, [
'IGNORE' ] );
471 if ( count( $tagsToRemove ) ) {
473 foreach ( $tagsToRemove as $tag ) {
474 $conds = array_filter(
476 'ct_rc_id' => $rc_id,
477 'ct_log_id' => $log_id,
478 'ct_rev_id' => $rev_id,
479 'ct_tag_id' => $changeTagDefStore->getId( $tag ),
482 $dbw->delete( self::CHANGE_TAG, $conds, __METHOD__ );
483 if ( $dbw->affectedRows() ) {
485 $dbw->onTransactionPreCommitOrIdle(
static function () use ( $dbw, $tag, $fname ) {
487 self::CHANGE_TAG_DEF,
488 [
'ctd_count = ctd_count - 1' ],
489 [
'ctd_name' => $tag ],
494 self::CHANGE_TAG_DEF,
495 [
'ctd_name' => $tag,
'ctd_count' => 0,
'ctd_user_defined' => 0 ],
503 $services = MediaWikiServices::getInstance();
504 $userObj = $user ? $services->getUserFactory()->newFromUserIdentity( $user ) :
null;
505 (
new HookRunner( $services->getHookContainer() ) )->onChangeTagsAfterUpdateTags(
506 $tagsToAdd, $tagsToRemove, $prevTags, $rc_id, $rev_id, $log_id, $params, $rc, $userObj );
508 return [ $tagsToAdd, $tagsToRemove, $prevTags ];
526 return MediaWikiServices::getInstance()->getChangeTagsStore()->getTagsWithData( $db, $rc_id, $rev_id, $log_id );
540 return array_keys( self::getTagsWithData( $db, $rc_id, $rev_id, $log_id ) );
555 $tags = array_values( $tags );
556 $count = count( $tags );
558 $lang->commaList( $tags ), $count );
559 $status->value = $tags;
583 $services = MediaWikiServices::getInstance();
584 if ( $performer !==
null ) {
585 if ( !$performer->isAllowed(
'applychangetags' ) ) {
589 if ( $checkBlock && $performer->getBlock() && $performer->getBlock()->isSitewide() ) {
591 'tags-apply-blocked',
592 $performer->getUser()->getName()
597 $user = $services->getUserFactory()->newFromAuthority( $performer );
602 (
new HookRunner( $services->getHookContainer() ) )->onChangeTagsAllowedAdd( $allowedTags, $tags, $user );
603 $disallowedTags = array_diff( $tags, $allowedTags );
604 if ( $disallowedTags ) {
606 'tags-apply-not-allowed-multi', $disallowedTags );
633 array $tags, $rc_id, $rev_id, $log_id, $params,
Authority $performer
637 if ( !$result->isOK() ) {
638 $result->value =
null;
667 if ( $performer !==
null ) {
668 if ( !$performer->isAllowed(
'changetags' ) ) {
672 if ( $performer->getBlock() && $performer->getBlock()->isSitewide() ) {
674 'tags-update-blocked',
675 $performer->getUser()->getName()
684 $diff = array_diff( $tagsToAdd, $explicitlyDefinedTags );
687 'tags-update-add-not-allowed-multi', $diff );
691 if ( $tagsToRemove ) {
696 $intersect = array_intersect( $tagsToRemove, $softwareDefinedTags );
699 'tags-update-remove-not-allowed-multi', $intersect );
737 $rc_id, $rev_id, $log_id, $params,
string $reason,
Authority $performer
739 if ( !$tagsToAdd && !$tagsToRemove ) {
749 $tagsToRemove ??= [];
753 if ( !$result->isOK() ) {
754 $result->value =
null;
759 $user = MediaWikiServices::getInstance()->getUserFactory()->newFromAuthority( $performer );
760 if ( $user->pingLimiter(
'changetags' ) ) {
766 $tagsToRemove, $rc_id, $rev_id, $log_id, $params,
null, $user );
767 if ( !$tagsAdded && !$tagsRemoved ) {
778 $logEntry->setPerformer( $performer->
getUser() );
779 $logEntry->setComment( $reason );
783 $revisionRecord = MediaWikiServices::getInstance()
784 ->getRevisionLookup()
785 ->getRevisionById( $rev_id );
786 if ( $revisionRecord ) {
787 $logEntry->setTarget( $revisionRecord->getPageAsLinkTarget() );
789 } elseif ( $log_id ) {
796 if ( !$logEntry->getTarget() ) {
802 '4::revid' => $rev_id,
803 '5::logid' => $log_id,
804 '6:list:tagsAdded' => $tagsAdded,
805 '7:number:tagsAddedCount' => count( $tagsAdded ),
806 '8:list:tagsRemoved' => $tagsRemoved,
807 '9:number:tagsRemovedCount' => count( $tagsRemoved ),
808 'initialTags' => $initialTags,
810 $logEntry->setParameters( $logParams );
811 $logEntry->setRelations( [
'Tag' => array_merge( $tagsAdded, $tagsRemoved ) ] );
813 $dbw = MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->getPrimaryDatabase();
814 $logId = $logEntry->insert( $dbw );
816 $logEntry->publish( $logId,
'udp' );
820 'addedTags' => $tagsAdded,
821 'removedTags' => $tagsRemoved,
846 &$join_conds, &$options, $filter_tag =
'',
bool $exclude =
false
848 $useTagFilter = MediaWikiServices::getInstance()->getMainConfig()->get(
849 MainConfigNames::UseTagFilter );
852 $tables = (array)$tables;
853 $fields = (array)$fields;
854 $conds = (array)$conds;
855 $options = (array)$options;
863 if ( in_array(
'recentchanges', $tables ) ) {
864 $join_cond = self::DISPLAY_TABLE_ALIAS .
'.ct_rc_id=rc_id';
865 } elseif ( in_array(
'logging', $tables ) ) {
866 $join_cond = self::DISPLAY_TABLE_ALIAS .
'.ct_log_id=log_id';
867 } elseif ( in_array(
'revision', $tables ) ) {
868 $join_cond = self::DISPLAY_TABLE_ALIAS .
'.ct_rev_id=rev_id';
869 } elseif ( in_array(
'archive', $tables ) ) {
870 $join_cond = self::DISPLAY_TABLE_ALIAS .
'.ct_rev_id=ar_rev_id';
872 throw new InvalidArgumentException(
'Unable to determine appropriate JOIN condition for tagging.' );
875 if ( !$useTagFilter ) {
879 if ( !is_array( $filter_tag ) ) {
881 $filter_tag = (string)$filter_tag;
884 if ( $filter_tag !== [] && $filter_tag !==
'' ) {
889 $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore();
890 foreach ( (array)$filter_tag as $filterTagName ) {
892 $filterTagIds[] = $changeTagDefStore->getId( $filterTagName );
898 if ( $filterTagIds !== [] ) {
902 [ $join_cond, self::DISPLAY_TABLE_ALIAS .
'.ct_tag_id' => $filterTagIds ]
904 $conds[] = self::DISPLAY_TABLE_ALIAS .
".ct_tag_id IS NULL";
909 if ( $filterTagIds !== [] ) {
910 $conds[self::DISPLAY_TABLE_ALIAS .
'.ct_tag_id'] = $filterTagIds;
917 is_array( $filter_tag ) && count( $filter_tag ) > 1 &&
918 !in_array(
'DISTINCT', $options )
920 $options[] =
'DISTINCT';
933 $tagTable = self::CHANGE_TAG;
934 if ( self::$avoidReopeningTablesForTesting && defined(
'MW_PHPUNIT_TEST' ) ) {
937 if ( $db->getType() ===
'mysql' ) {
946 $tagTable =
'change_tag_for_display_query';
947 if ( !$db->tableExists( $tagTable ) ) {
949 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $db->tableName( $tagTable )
950 .
' LIKE ' . $db->tableName( self::CHANGE_TAG ),
954 'INSERT IGNORE INTO ' . $db->tableName( $tagTable )
955 .
' SELECT * FROM ' . $db->tableName( self::CHANGE_TAG ),
973 return MediaWikiServices::getInstance()->getChangeTagsStore()->makeTagSummarySubquery( $tables );
994 $config = $context->getConfig();
995 if ( !$config->get( MainConfigNames::UseTagFilter ) ||
996 !count( self::listDefinedTags() ) ) {
1002 foreach ( $tags as $tagInfo ) {
1003 $autocomplete[ $tagInfo[
'label'] ] = $tagInfo[
'name'];
1009 [
'for' =>
'tagfilter' ],
1010 $context->msg(
'tag-filter' )->parse()
1017 $data[] =
new OOUI\ComboBoxInputWidget( [
1018 'id' =>
'tagfilter',
1019 'name' =>
'tagfilter',
1020 'value' => $selected,
1021 'classes' =>
'mw-tagfilter-input',
1022 'options' => $options,
1025 $datalist =
new XmlSelect(
false,
'tagfilter-datalist' );
1026 $datalist->setTagName(
'datalist' );
1027 $datalist->addOptions( $autocomplete );
1034 'class' =>
'mw-tagfilter-input mw-ui-input mw-ui-input-inline',
1035 'id' =>
'tagfilter',
1036 'list' =>
'tagfilter-datalist',
1038 ) . $datalist->getHTML();
1054 MediaWikiServices::getInstance()->getChangeTagsStore()->defineTag( $tag );
1067 MediaWikiServices::getInstance()->getChangeTagsStore()->undefineTag( $tag );
1080 if ( $performer !==
null ) {
1081 if ( !$performer->isAllowed(
'managechangetags' ) ) {
1084 if ( $performer->getBlock() && $performer->getBlock()->isSitewide() ) {
1086 'tags-manage-blocked',
1087 $performer->getUser()->getName()
1096 if ( in_array( $tag, $definedTags ) ) {
1102 if ( !isset( $tagUsage[$tag] ) ) {
1127 bool $ignoreWarnings =
false, array $logEntryTags = []
1131 if ( $ignoreWarnings ? !$result->isOK() : !$result->isGood() ) {
1132 $result->value =
null;
1140 $changeTagStore = MediaWikiServices::getInstance()->getChangeTagsStore();
1141 $logId = $changeTagStore->logTagManagementAction(
'activate', $tag, $reason, $performer->
getUser(),
1142 null, $logEntryTags );
1157 if ( $performer !==
null ) {
1158 if ( !$performer->isAllowed(
'managechangetags' ) ) {
1161 if ( $performer->getBlock() && $performer->getBlock()->isSitewide() ) {
1163 'tags-manage-blocked',
1164 $performer->getUser()->getName()
1171 if ( !in_array( $tag, $explicitlyDefinedTags ) ) {
1195 bool $ignoreWarnings =
false, array $logEntryTags = []
1199 if ( $ignoreWarnings ? !$result->isOK() : !$result->isGood() ) {
1200 $result->value =
null;
1208 $changeTagStore = MediaWikiServices::getInstance()->getChangeTagsStore();
1209 $logId = $changeTagStore->logTagManagementAction(
'deactivate', $tag, $reason,
1210 $performer->
getUser(),
null, $logEntryTags );
1224 if ( $tag ===
'' ) {
1232 if ( strpos( $tag,
',' ) !==
false || strpos( $tag,
'|' ) !==
false
1233 || strpos( $tag,
'/' ) !==
false ) {
1260 $services = MediaWikiServices::getInstance();
1261 if ( $performer !==
null ) {
1262 if ( !$performer->isAllowed(
'managechangetags' ) ) {
1265 if ( $performer->getBlock() && $performer->getBlock()->isSitewide() ) {
1267 'tags-manage-blocked',
1268 $performer->getUser()->getName()
1272 $user = $services->getUserFactory()->newFromAuthority( $performer );
1276 if ( !$status->isGood() ) {
1282 if ( isset( $tagUsage[$tag] ) || in_array( $tag, self::listDefinedTags() ) ) {
1288 (
new HookRunner( $services->getHookContainer() ) )->onChangeTagCanCreate( $tag, $user, $canCreateResult );
1289 return $canCreateResult;
1312 bool $ignoreWarnings =
false, array $logEntryTags = []
1316 if ( $ignoreWarnings ? !$result->isOK() : !$result->isGood() ) {
1317 $result->value =
null;
1325 $changeTagStore = MediaWikiServices::getInstance()->getChangeTagsStore();
1326 $logId = $changeTagStore->logTagManagementAction(
'create', $tag, $reason,
1327 $performer->
getUser(),
null, $logEntryTags );
1346 return MediaWikiServices::getInstance()->getChangeTagsStore()->deleteTagEverywhere( $tag );
1364 $services = MediaWikiServices::getInstance();
1365 if ( $performer !==
null ) {
1366 if ( !$performer->isAllowed(
'deletechangetags' ) ) {
1369 if ( $performer->getBlock() && $performer->getBlock()->isSitewide() ) {
1371 'tags-manage-blocked',
1372 $performer->getUser()->getName()
1376 $user = $services->getUserFactory()->newFromAuthority( $performer );
1379 if ( !isset( $tagUsage[$tag] ) && !in_array( $tag, self::listDefinedTags() ) ) {
1383 if ( $flags !== self::BYPASS_MAX_USAGE_CHECK &&
1384 isset( $tagUsage[$tag] ) &&
1385 $tagUsage[$tag] > self::MAX_DELETE_USES
1387 return Status::newFatal(
'tags-delete-too-many-uses', $tag, self::MAX_DELETE_USES );
1391 if ( in_array( $tag, $softwareDefined ) ) {
1400 (
new HookRunner( $services->getHookContainer() ) )->onChangeTagCanDelete( $tag, $user, $status );
1422 bool $ignoreWarnings =
false, array $logEntryTags = []
1426 if ( $ignoreWarnings ? !$result->isOK() : !$result->isGood() ) {
1427 $result->value =
null;
1433 $hitcount = $tagUsage[$tag] ?? 0;
1437 if ( !$deleteResult->isOK() ) {
1438 return $deleteResult;
1442 $changeTagStore = MediaWikiServices::getInstance()->getChangeTagsStore();
1443 $logId = $changeTagStore->logTagManagementAction(
'delete', $tag, $reason, $performer->
getUser(),
1444 $hitcount, $logEntryTags );
1446 $deleteResult->value = $logId;
1447 return $deleteResult;
1459 $hookContainer = MediaWikiServices::getInstance()->getHookContainer();
1460 if ( !$hookContainer->isRegistered(
'ChangeTagsListActive' ) ) {
1463 $hookRunner =
new HookRunner( $hookContainer );
1464 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1465 return $cache->getWithSetCallback(
1466 $cache->makeKey(
'active-tags' ),
1467 WANObjectCache::TTL_MINUTE * 5,
1468 static function ( $oldValue, &$ttl, array &$setOpts ) use ( $tags, $hookRunner ) {
1472 $hookRunner->onChangeTagsListActive( $tags );
1476 'checkKeys' => [ $cache->makeKey(
'active-tags' ) ],
1477 'lockTSE' => WANObjectCache::TTL_MINUTE * 5,
1478 'pcTTL' => WANObjectCache::TTL_PROC_LONG
1493 return array_values( array_unique( array_merge( $tags1, $tags2 ) ) );
1505 $fname = __METHOD__;
1507 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1508 return $cache->getWithSetCallback(
1509 $cache->makeKey(
'valid-tags-db' ),
1510 WANObjectCache::TTL_MINUTE * 5,
1511 static function ( $oldValue, &$ttl, array &$setOpts ) use ( $fname ) {
1514 $setOpts += Database::getCacheSetOptions(
$dbr );
1515 $tags =
$dbr->newSelectQueryBuilder()
1516 ->select(
'ctd_name' )
1517 ->from( self::CHANGE_TAG_DEF )
1518 ->where( [
'ctd_user_defined' => 1 ] )
1520 ->fetchFieldValues();
1522 return array_unique( $tags );
1525 'checkKeys' => [ $cache->makeKey(
'valid-tags-db' ) ],
1526 'lockTSE' => WANObjectCache::TTL_MINUTE * 5,
1527 'pcTTL' => WANObjectCache::TTL_PROC_LONG
1544 $hookContainer = MediaWikiServices::getInstance()->getHookContainer();
1545 if ( !$hookContainer->isRegistered(
'ListDefinedTags' ) ) {
1548 $hookRunner =
new HookRunner( $hookContainer );
1549 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1550 return $cache->getWithSetCallback(
1551 $cache->makeKey(
'valid-tags-hook' ),
1552 WANObjectCache::TTL_MINUTE * 5,
1553 static function ( $oldValue, &$ttl, array &$setOpts ) use ( $tags, $hookRunner ) {
1556 $hookRunner->onListDefinedTags( $tags );
1557 return array_unique( $tags );
1560 'checkKeys' => [ $cache->makeKey(
'valid-tags-hook' ) ],
1561 'lockTSE' => WANObjectCache::TTL_MINUTE * 5,
1562 'pcTTL' => WANObjectCache::TTL_PROC_LONG
1574 MediaWikiServices::getInstance()->getChangeTagsStore()->purgeTagCacheAll();
1586 return MediaWikiServices::getInstance()->getChangeTagsStore()->tagUsageStatistics();
1593 private const TAG_DESC_CHARACTER_LIMIT = 120;
1620 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1621 return $cache->getWithSetCallback(
1622 $cache->makeKey(
'tags-list-summary',
$lang->getCode() ),
1623 WANObjectCache::TTL_DAY,
1624 static function ( $oldValue, &$ttl, array &$setOpts ) use ( $localizer ) {
1629 foreach ( self::listDefinedTags() as $tagName ) {
1631 $hits = $tagHitCounts[$tagName] ?? 0;
1641 'labelMsg' => (bool)$labelMsg,
1642 'label' => $labelMsg ? $labelMsg->plain() : $tagName,
1643 'descriptionMsg' => (bool)$descriptionMsg,
1644 'description' => $descriptionMsg ? $descriptionMsg->plain() :
'',
1667 foreach ( $tags as &$tagInfo ) {
1668 if ( $tagInfo[
'labelMsg'] ) {
1670 $labelMsg =
new RawMessage( $tagInfo[
'label'] );
1673 $tagInfo[
'label'] = $localizer->
msg(
'tag-hidden', $tagInfo[
'name'] )->text();
1675 if ( $tagInfo[
'descriptionMsg'] ) {
1676 $descriptionMsg =
new RawMessage( $tagInfo[
'description'] );
1677 $tagInfo[
'description'] =
$lang->truncateForVisual(
1679 self::TAG_DESC_CHARACTER_LIMIT
1682 unset( $tagInfo[
'labelMsg'] );
1683 unset( $tagInfo[
'descriptionMsg'] );
1687 usort( $tags,
static function ( $a, $b ) {
1688 return strcasecmp( $a[
'label'], $b[
'label'] );
1708 return $performer->
isAllowed(
'changetags' ) && (bool)self::listExplicitlyDefinedTags();
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Base class for language-specific code.
Class for creating new log entries and inserting them into the database.
A class containing constants representing the names of configuration variables.
static plaintextParam( $plaintext)
Utility class for creating new RC entries.
static getMain()
Get the RequestContext object associated with the main request.
static suggestTarget( $target, array $ids)
Suggest a target for the revision deletion Optionally override this function.
static escapeClass( $class)
Given a value, escape it so that it can be used as a CSS class and return it.
static stripAllTags( $html)
Take a fragment of (potentially invalid) HTML and return a version with any tags removed,...
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
static newFatal( $message,... $parameters)
Factory function for fatal errors.
static newGood( $value=null)
Factory function for good results.
Class for generating HTML <select> or <datalist> elements.
static listDropDownOptionsOoui( $options)
Convert options for a drop-down box into a format accepted by OOUI\DropdownInputWidget etc.
static input( $name, $size=false, $value=false, $attribs=[])
Convenience function to build an HTML text input field.
static tags( $element, $attribs, $contents)
Same as Xml::element(), but does not escape contents.
Interface for objects which can provide a MediaWiki context on request.
Interface for localizing messages in MediaWiki.
msg( $key,... $params)
This is the method for getting translated interface messages.
if(!isset( $args[0])) $lang