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