addDescription( 'Re-assign users from an old group to a new one' ); $this->addArg( 'oldgroup', 'Old user group key', true ); $this->addArg( 'newgroup', 'New user group key', true ); $this->setBatchSize( 200 ); } public function execute() { $count = 0; $oldGroup = $this->getArg( 0 ); $newGroup = $this->getArg( 1 ); $dbw = $this->getDB( DB_MASTER ); $batchSize = $this->getBatchSize(); $start = $dbw->selectField( 'user_groups', 'MIN(ug_user)', [ 'ug_group' => $oldGroup ], __FUNCTION__ ); $end = $dbw->selectField( 'user_groups', 'MAX(ug_user)', [ 'ug_group' => $oldGroup ], __FUNCTION__ ); if ( $start === null ) { $this->fatalError( "Nothing to do - no users in the '$oldGroup' group" ); } # Do remaining chunk $end += $batchSize - 1; $blockStart = $start; $blockEnd = $start + $batchSize - 1; // Migrate users over in batches... while ( $blockEnd <= $end ) { $affected = 0; $this->output( "Doing users $blockStart to $blockEnd\n" ); $this->beginTransaction( $dbw, __METHOD__ ); $dbw->update( 'user_groups', [ 'ug_group' => $newGroup ], [ 'ug_group' => $oldGroup, "ug_user BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ], __METHOD__, [ 'IGNORE' ] ); $affected += $dbw->affectedRows(); // Delete rows that the UPDATE operation above had to ignore. // This happens when a user is in both the old and new group. // Updating the row for the old group membership failed since // user/group is UNIQUE. $dbw->delete( 'user_groups', [ 'ug_group' => $oldGroup, "ug_user BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ], __METHOD__ ); $affected += $dbw->affectedRows(); $this->commitTransaction( $dbw, __METHOD__ ); // Clear cache for the affected users (T42340) if ( $affected > 0 ) { // XXX: This also invalidates cache of unaffected users that // were in the new group and not in the group. $res = $dbw->select( 'user_groups', 'ug_user', [ 'ug_group' => $newGroup, "ug_user BETWEEN " . (int)$blockStart . " AND " . (int)$blockEnd ], __METHOD__ ); if ( $res !== false ) { foreach ( $res as $row ) { $user = User::newFromId( $row->ug_user ); $user->invalidateCache(); } } } $count += $affected; $blockStart += $batchSize; $blockEnd += $batchSize; wfWaitForSlaves(); } $this->output( "Done! $count users in group '$oldGroup' are now in '$newGroup' instead.\n" ); } } $maintClass = MigrateUserGroup::class; require_once RUN_MAINTENANCE_IF_MAIN;