MediaWiki  master
migrateUserGroup.php
Go to the documentation of this file.
1 <?php
24 require_once __DIR__ . '/Maintenance.php';
25 
32  public function __construct() {
33  parent::__construct();
34  $this->addDescription( 'Re-assign users from an old group to a new one' );
35  $this->addArg( 'oldgroup', 'Old user group key', true );
36  $this->addArg( 'newgroup', 'New user group key', true );
37  $this->setBatchSize( 200 );
38  }
39 
40  public function execute() {
41  $count = 0;
42  $oldGroup = $this->getArg( 0 );
43  $newGroup = $this->getArg( 1 );
44  $dbw = $this->getDB( DB_MASTER );
45  $batchSize = $this->getBatchSize();
46  $start = $dbw->selectField( 'user_groups', 'MIN(ug_user)',
47  [ 'ug_group' => $oldGroup ], __FUNCTION__ );
48  $end = $dbw->selectField( 'user_groups', 'MAX(ug_user)',
49  [ 'ug_group' => $oldGroup ], __FUNCTION__ );
50  if ( $start === null ) {
51  $this->fatalError( "Nothing to do - no users in the '$oldGroup' group" );
52  }
53  # Do remaining chunk
54  $end += $batchSize - 1;
55  $blockStart = $start;
56  $blockEnd = $start + $batchSize - 1;
57  // Migrate users over in batches...
58  while ( $blockEnd <= $end ) {
59  $affected = 0;
60  $this->output( "Doing users $blockStart to $blockEnd\n" );
61 
62  $this->beginTransaction( $dbw, __METHOD__ );
63  $dbw->update( 'user_groups',
64  [ 'ug_group' => $newGroup ],
65  [ 'ug_group' => $oldGroup,
66  "ug_user BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ],
67  __METHOD__,
68  [ 'IGNORE' ]
69  );
70  $affected += $dbw->affectedRows();
71  // Delete rows that the UPDATE operation above had to ignore.
72  // This happens when a user is in both the old and new group.
73  // Updating the row for the old group membership failed since
74  // user/group is UNIQUE.
75  $dbw->delete( 'user_groups',
76  [ 'ug_group' => $oldGroup,
77  "ug_user BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ],
78  __METHOD__
79  );
80  $affected += $dbw->affectedRows();
81  $this->commitTransaction( $dbw, __METHOD__ );
82 
83  // Clear cache for the affected users (T42340)
84  if ( $affected > 0 ) {
85  // XXX: This also invalidates cache of unaffected users that
86  // were in the new group and not in the group.
87  $res = $dbw->select( 'user_groups', 'ug_user',
88  [ 'ug_group' => $newGroup,
89  "ug_user BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ],
90  __METHOD__
91  );
92  if ( $res !== false ) {
93  foreach ( $res as $row ) {
94  $user = User::newFromId( $row->ug_user );
95  $user->invalidateCache();
96  }
97  }
98  }
99 
100  $count += $affected;
101  $blockStart += $batchSize;
102  $blockEnd += $batchSize;
103  }
104  $this->output( "Done! $count users in group '$oldGroup' are now in '$newGroup' instead.\n" );
105  }
106 }
107 
108 $maintClass = MigrateUserGroup::class;
109 require_once RUN_MAINTENANCE_IF_MAIN;
commitTransaction(IDatabase $dbw, $fname)
Commit the transcation on a DB handle and wait for replica DBs to catch up.
getArg( $argId=0, $default=null)
Get an argument.
const RUN_MAINTENANCE_IF_MAIN
Definition: Maintenance.php:39
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
Definition: Maintenance.php:86
setBatchSize( $s=0)
Set the batch size.
const DB_MASTER
Definition: defines.php:26
addDescription( $text)
Set the description text.
addArg( $arg, $description, $required=true)
Add some args that are needed.
output( $out, $channel=null)
Throw some output to the user.
Maintenance script that re-assigns users from an old group to a new one.
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition: User.php:560
getBatchSize()
Returns batch size.
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
getDB( $db, $groups=[], $dbDomain=false)
Returns a database to be used by current maintenance script.
beginTransaction(IDatabase $dbw, $fname)
Begin a transcation on a DB.