Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
31.11% covered (danger)
31.11%
14 / 45
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
DeleteTag
31.11% covered (danger)
31.11%
14 / 45
50.00% covered (danger)
50.00%
1 / 2
13.17
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 execute
24.39% covered (danger)
24.39%
10 / 41
0.00% covered (danger)
0.00%
0 / 1
10.92
1<?php
2
3/**
4 * Remove a revision tag from edits and log entries it was applied to.
5 * @see bug T75181
6 */
7
8use MediaWiki\Maintenance\Maintenance;
9use MediaWiki\Storage\NameTableAccessException;
10
11// @codeCoverageIgnoreStart
12require_once __DIR__ . '/Maintenance.php';
13// @codeCoverageIgnoreEnd
14
15class DeleteTag extends Maintenance {
16    public function __construct() {
17        parent::__construct();
18        $this->addDescription( 'Deletes a change tag' );
19        $this->addArg( 'tag name', 'Name of the tag to delete' );
20        $this->setBatchSize( 500 );
21    }
22
23    public function execute() {
24        $dbw = $this->getPrimaryDB();
25        $services = $this->getServiceContainer();
26        $defStore = $services->getChangeTagDefStore();
27
28        $tag = $this->getArg( 0 );
29        try {
30            $tagId = $defStore->getId( $tag );
31        } catch ( NameTableAccessException $ex ) {
32            $this->fatalError( "Tag '$tag' not found" );
33        }
34
35        $status = ChangeTags::canDeleteTag( $tag, null, ChangeTags::BYPASS_MAX_USAGE_CHECK );
36        if ( !$status->isOK() ) {
37            $this->fatalError( $status );
38        }
39
40        $this->output( "Deleting tag '$tag'...\n" );
41
42        // Make the tag impossible to add by users while we're deleting it and drop the
43        // usage counter to zero
44        $dbw->newUpdateQueryBuilder()
45            ->update( 'change_tag_def' )
46            ->set( [
47                'ctd_user_defined' => 0,
48                'ctd_count' => 0,
49            ] )
50            ->where( [ 'ctd_id' => $tagId ] )
51            ->caller( __METHOD__ )->execute();
52        $this->getServiceContainer()->getChangeTagsStore()->purgeTagCacheAll();
53
54        // Iterate over change_tag, deleting rows in batches
55        $count = 0;
56        do {
57            $ids = $dbw->newSelectQueryBuilder()
58                ->select( 'ct_id' )
59                ->from( 'change_tag' )
60                ->where( [ 'ct_tag_id' => $tagId ] )
61                ->limit( $this->getBatchSize() )
62                ->caller( __METHOD__ )
63                ->fetchFieldValues();
64
65            if ( !$ids ) {
66                break;
67            }
68            $dbw->newDeleteQueryBuilder()
69                ->deleteFrom( 'change_tag' )
70                ->where( [ 'ct_id' => $ids ] )
71                ->caller( __METHOD__ )->execute();
72            $count += $dbw->affectedRows();
73            $this->output( "$count\n" );
74            $this->waitForReplication();
75        } while ( true );
76        $this->output( "The tag has been removed from $count revisions, deleting the tag itself...\n" );
77
78        $this->getServiceContainer()->getChangeTagsStore()->deleteTagEverywhere( $tag );
79        $this->output( "Done.\n" );
80    }
81}
82
83// @codeCoverageIgnoreStart
84$maintClass = DeleteTag::class;
85require_once RUN_MAINTENANCE_IF_MAIN;
86// @codeCoverageIgnoreEnd