Join decomposition on change_tag and change_tag_def when filtering
[lhc/web/wiklou.git] / includes / changetags / ChangeTags.php
index 3bb777e..008a2f6 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\NameTableAccessException;
 use Wikimedia\Rdbms\Database;
 
 class ChangeTags {
@@ -201,9 +202,8 @@ class ChangeTags {
                }
 
                $taglessDesc = Sanitizer::stripAllTags( $originalDesc->parse() );
-               $escapedDesc = Sanitizer::escapeHtmlAllowEntities( $taglessDesc );
 
-               return $context->getLanguage()->truncateForVisual( $escapedDesc, $length );
+               return $context->getLanguage()->truncateForVisual( $taglessDesc, $length );
        }
 
        /**
@@ -343,11 +343,10 @@ class ChangeTags {
                }
 
                // insert a row into change_tag for each new tag
+               $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore();
                if ( count( $tagsToAdd ) ) {
                        $changeTagMapping = [];
                        if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_OLD ) {
-                               $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore();
-
                                foreach ( $tagsToAdd as $tag ) {
                                        $changeTagMapping[$tag] = $changeTagDefStore->acquireId( $tag );
                                }
@@ -362,13 +361,18 @@ class ChangeTags {
 
                        $tagsRows = [];
                        foreach ( $tagsToAdd as $tag ) {
+                               if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+                                       $tagName = null;
+                               } else {
+                                       $tagName = $tag;
+                               }
                                // Filter so we don't insert NULLs as zero accidentally.
                                // Keep in mind that $rc_id === null means "I don't care/know about the
                                // rc_id, just delete $tag on this revision/log entry". It doesn't
                                // mean "only delete tags on this revision/log WHERE rc_id IS NULL".
                                $tagsRows[] = array_filter(
                                        [
-                                               'ct_tag' => $tag,
+                                               'ct_tag' => $tagName,
                                                'ct_rc_id' => $rc_id,
                                                'ct_log_id' => $log_id,
                                                'ct_rev_id' => $rev_id,
@@ -385,12 +389,20 @@ class ChangeTags {
                // delete from change_tag
                if ( count( $tagsToRemove ) ) {
                        foreach ( $tagsToRemove as $tag ) {
+                               if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+                                       $tagName = null;
+                                       $tagId = $changeTagDefStore->getId( $tag );
+                               } else {
+                                       $tagName = $tag;
+                                       $tagId = null;
+                               }
                                $conds = array_filter(
                                        [
-                                               'ct_tag' => $tag,
+                                               'ct_tag' => $tagName,
                                                'ct_rc_id' => $rc_id,
                                                'ct_log_id' => $log_id,
-                                               'ct_rev_id' => $rev_id
+                                               'ct_rev_id' => $rev_id,
+                                               'ct_tag_id' => $tagId,
                                        ]
                                );
                                $dbw->delete( 'change_tag', $conds, __METHOD__ );
@@ -770,7 +782,7 @@ class ChangeTags {
        public static function modifyDisplayQuery( &$tables, &$fields, &$conds,
                &$join_conds, &$options, $filter_tag = ''
        ) {
-               global $wgUseTagFilter;
+               global $wgUseTagFilter, $wgChangeTagsSchemaMigrationStage;
 
                // Normalize to arrays
                $tables = (array)$tables;
@@ -791,8 +803,18 @@ class ChangeTags {
                        throw new MWException( 'Unable to determine appropriate JOIN condition for tagging.' );
                }
 
+               $tagTables[] = 'change_tag';
+               if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+                       $tagTables[] = 'change_tag_def';
+                       $join_cond_ts_tags = [ $join_cond, 'ct_tag_id=ctd_id' ];
+                       $field = 'ctd_name';
+               } else {
+                       $field = 'ct_tag';
+                       $join_cond_ts_tags = $join_cond;
+               }
+
                $fields['ts_tags'] = wfGetDB( DB_REPLICA )->buildGroupConcatField(
-                       ',', 'change_tag', 'ct_tag', $join_cond
+                       ',', $tagTables, $field, $join_cond_ts_tags
                );
 
                if ( $wgUseTagFilter && $filter_tag ) {
@@ -801,7 +823,23 @@ class ChangeTags {
 
                        $tables[] = 'change_tag';
                        $join_conds['change_tag'] = [ 'INNER JOIN', $join_cond ];
-                       $conds['ct_tag'] = $filter_tag;
+                       if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+                               $filterTagIds = [];
+                               $changeTagDefStore = MediaWikiServices::getInstance()->getChangeTagDefStore();
+                               foreach ( (array)$filter_tag as $filterTagName ) {
+                                       try {
+                                               $filterTagIds[] = $changeTagDefStore->getId( $filterTagName );
+                                       } catch ( NameTableAccessException $exception ) {
+                                               // Return nothing.
+                                               $conds[] = '0';
+                                               break;
+                                       };
+                               }
+                               $conds['ct_tag_id'] = $filterTagIds;
+                       } else {
+                               $conds['ct_tag'] = $filter_tag;
+                       }
+
                        if (
                                is_array( $filter_tag ) && count( $filter_tag ) > 1 &&
                                !in_array( 'DISTINCT', $options )
@@ -916,8 +954,8 @@ class ChangeTags {
                if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_OLD ) {
                        $dbw->update(
                                'change_tag_def',
-                               [ 'ctd_name' => $tag ],
                                [ 'ctd_user_defined' => 0 ],
+                               [ 'ctd_name' => $tag ],
                                __METHOD__
                        );
 
@@ -1184,7 +1222,7 @@ class ChangeTags {
         * Extensions should NOT use this function; they can use the ListDefinedTags
         * hook instead.
         *
-        * Includes a call to ChangeTag::canDeleteTag(), so your code doesn't need to
+        * Includes a call to ChangeTag::canCreateTag(), so your code doesn't need to
         * do that.
         *
         * @param string $tag
@@ -1237,10 +1275,17 @@ class ChangeTags {
                // delete from valid_tag and/or set ctd_user_defined = 0
                self::undefineTag( $tag );
 
+               if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+                       $tagId = MediaWikiServices::getInstance()->getChangeTagDefStore()->getId( $tag );
+                       $conditions = [ 'ct_tag_id' => $tagId ];
+               } else {
+                       $conditions = [ 'ct_tag' => $tag ];
+               }
+
                // find out which revisions use this tag, so we can delete from tag_summary
                $result = $dbw->select( 'change_tag',
-                       [ 'ct_rc_id', 'ct_log_id', 'ct_rev_id', 'ct_tag' ],
-                       [ 'ct_tag' => $tag ],
+                       [ 'ct_rc_id', 'ct_log_id', 'ct_rev_id' ],
+                       $conditions,
                        __METHOD__ );
                foreach ( $result as $row ) {
                        // remove the tag from the relevant row of tag_summary
@@ -1251,7 +1296,12 @@ class ChangeTags {
                }
 
                // delete from change_tag
-               $dbw->delete( 'change_tag', [ 'ct_tag' => $tag ], __METHOD__ );
+               if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_WRITE_BOTH ) {
+                       $tagId = MediaWikiServices::getInstance()->getChangeTagDefStore()->getId( $tag );
+                       $dbw->delete( 'change_tag', [ 'ct_tag_id' => $tagId ], __METHOD__ );
+               } else {
+                       $dbw->delete( 'change_tag', [ 'ct_tag' => $tag ], __METHOD__ );
+               }
 
                if ( $wgChangeTagsSchemaMigrationStage > MIGRATION_OLD ) {
                        $dbw->delete( 'change_tag_def', [ 'ctd_name' => $tag ], __METHOD__ );