*/
const MAX_DELETE_USES = 5000;
+ private static $definedSoftwareTags = [
+ 'mw-contentmodelchange',
+ 'mw-new-redirect',
+ 'mw-removed-redirect',
+ 'mw-changed-redirect-target',
+ 'mw-blank',
+ 'mw-replace',
+ 'mw-rollback',
+ 'mw-undo',
+ ];
+
/**
- * @var string[]
+ * Loads defined core tags, checks for invalid types (if not array),
+ * and filters for supported and enabled (if $all is false) tags only.
+ *
+ * @param bool $all If true, return all valid defined tags. Otherwise, return only enabled ones.
+ * @return array Array of all defined/enabled tags.
*/
- private static $coreTags = [ 'mw-contentmodelchange' ];
+ public static function getSoftwareTags( $all = false ) {
+ global $wgSoftwareTags;
+ $softwareTags = [];
+
+ if ( !is_array( $wgSoftwareTags ) ) {
+ wfWarn( 'wgSoftwareTags should be associative array of enabled tags.
+ Please refer to documentation for the list of tags you can enable' );
+ return $softwareTags;
+ }
+
+ $availableSoftwareTags = !$all ?
+ array_keys( array_filter( $wgSoftwareTags ) ) :
+ array_keys( $wgSoftwareTags );
+
+ $softwareTags = array_intersect(
+ $availableSoftwareTags,
+ self::$definedSoftwareTags
+ );
+
+ return $softwareTags;
+ }
/**
* Creates HTML for the given tags
* exists, provided it is not disabled. If the message is disabled,
* we consider the tag hidden, and return false.
*
- * @param string $tag Tag
+ * @param string $tag
* @param IContextSource $context
* @return string|bool Tag description or false if tag is to be hidden.
* @since 1.25 Returns false if tag is to be hidden.
* or if message is disabled, returns false. Otherwise, returns the message object
* for the long description.
*
- * @param string $tag Tag
+ * @param string $tag
* @param IContextSource $context
* @return Message|bool Message object of the tag long description or false if
* there is no description.
sort( $prevTags );
sort( $newTags );
if ( $prevTags == $newTags ) {
- // No change.
return false;
}
if ( !$newTags ) {
- // no tags left, so delete the row altogether
+ // No tags left, so delete the row altogether
$dbw->delete( 'tag_summary', $tsConds, __METHOD__ );
} else {
- $dbw->replace( 'tag_summary',
- [ 'ts_rev_id', 'ts_rc_id', 'ts_log_id' ],
- array_filter( array_merge( $tsConds, [ 'ts_tags' => implode( ',', $newTags ) ] ) ),
- __METHOD__
- );
+ // Specify the non-DEFAULT value columns in the INSERT/REPLACE clause
+ $row = array_filter( [ 'ts_tags' => implode( ',', $newTags ) ] + $tsConds );
+ // Check the unique keys for conflicts, ignoring any NULL *_id values
+ $uniqueKeys = [];
+ foreach ( [ 'ts_rev_id', 'ts_rc_id', 'ts_log_id' ] as $uniqueColumn ) {
+ if ( isset( $row[$uniqueColumn] ) ) {
+ $uniqueKeys[] = [ $uniqueColumn ];
+ }
+ }
+
+ $dbw->replace( 'tag_summary', $uniqueKeys, $row, __METHOD__ );
}
return true;
* Handles selecting tags, and filtering.
* Needs $tables to be set up properly, so we can figure out which join conditions to use.
*
- * @param string|array $tables Table names, see Database::select
- * @param string|array $fields Fields used in query, see Database::select
- * @param string|array $conds Conditions used in query, see Database::select
- * @param array $join_conds Join conditions, see Database::select
- * @param array $options Options, see Database::select
- * @param bool|string $filter_tag Tag to select on
+ * WARNING: If $filter_tag contains more than one tag, this function will add DISTINCT,
+ * which may cause performance problems for your query unless you put the ID field of your
+ * table at the end of the ORDER BY, and set a GROUP BY equal to the ORDER BY. For example,
+ * if you had ORDER BY foo_timestamp DESC, you will now need GROUP BY foo_timestamp, foo_id
+ * ORDER BY foo_timestamp DESC, foo_id DESC.
+ *
+ * @param string|array &$tables Table names, see Database::select
+ * @param string|array &$fields Fields used in query, see Database::select
+ * @param string|array &$conds Conditions used in query, see Database::select
+ * @param array &$join_conds Join conditions, see Database::select
+ * @param string|array &$options Options, see Database::select
+ * @param string|array $filter_tag Tag(s) to select on
*
* @throws MWException When unable to determine appropriate JOIN condition for tagging
*/
public static function modifyDisplayQuery( &$tables, &$fields, &$conds,
- &$join_conds, &$options, $filter_tag = false ) {
- global $wgRequest, $wgUseTagFilter;
+ &$join_conds, &$options, $filter_tag = '' ) {
+ global $wgUseTagFilter;
- if ( $filter_tag === false ) {
- $filter_tag = $wgRequest->getVal( 'tagfilter' );
- }
+ // Normalize to arrays
+ $tables = (array)$tables;
+ $fields = (array)$fields;
+ $conds = (array)$conds;
+ $options = (array)$options;
- // Figure out which conditions can be done.
+ // Figure out which ID field to use
if ( in_array( 'recentchanges', $tables ) ) {
$join_cond = 'ct_rc_id=rc_id';
} elseif ( in_array( 'logging', $tables ) ) {
$tables[] = 'change_tag';
$join_conds['change_tag'] = [ 'INNER JOIN', $join_cond ];
- $conds['ct_tag'] = explode( '|', $filter_tag );
+ $conds['ct_tag'] = $filter_tag;
+ if (
+ is_array( $filter_tag ) && count( $filter_tag ) > 1 &&
+ !in_array( 'DISTINCT', $options )
+ ) {
+ $options[] = 'DISTINCT';
+ }
}
}
// tags cannot contain commas (used as a delimiter in tag_summary table),
// pipe (used as a delimiter between multiple tags in
- // modifyDisplayQuery), or slashes (would break tag description messages in
+ // SpecialRecentchanges and friends), or slashes (would break tag description messages in
// MediaWiki namespace)
if ( strpos( $tag, ',' ) !== false || strpos( $tag, '|' ) !== false
|| strpos( $tag, '/' ) !== false ) {
*/
public static function listSoftwareActivatedTags() {
// core active tags
- $tags = self::$coreTags;
+ $tags = self::getSoftwareTags();
if ( !Hooks::isRegistered( 'ChangeTagsListActive' ) ) {
return $tags;
}
*/
public static function listSoftwareDefinedTags() {
// core defined tags
- $tags = self::$coreTags;
+ $tags = self::getSoftwareTags( true );
if ( !Hooks::isRegistered( 'ListDefinedTags' ) ) {
return $tags;
}
*
* @see listSoftwareDefinedTags
* @deprecated since 1.28
+ * @return array
*/
public static function listExtensionDefinedTags() {
wfDeprecated( __METHOD__, '1.28' );