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