26require_once __DIR__ .
'/Maintenance.php';
47 'revactor_actor' => [
'revision_actor_temp',
'revactor_actor',
'revactor_rev' ],
48 'ar_actor' => [
'archive',
'ar_actor',
'ar_id' ],
49 'ipb_by_actor' => [
'ipblocks',
'ipb_by_actor',
'ipb_id' ],
50 'img_actor' => [
'image',
'img_actor',
'img_name' ],
51 'oi_actor' => [
'oldimage',
'oi_actor',
'oi_archive_name' ],
52 'fa_actor' => [
'filearchive',
'fa_actor',
'fa_id' ],
53 'rc_actor' => [
'recentchanges',
'rc_actor',
'rc_id' ],
54 'log_actor' => [
'logging',
'log_actor',
'log_id' ],
58 parent::__construct();
61 $this->
addOption(
'field',
'The name of a database field to process. '
62 .
'Possible values: ' . implode(
', ', array_keys( self::TABLES ) ),
64 $this->
addOption(
'skip',
'A comma-separated list of actor IDs to skip.',
66 $this->
addOption(
'overwrite-with',
'Replace missing actors with this user. '
67 .
'Typically, this would be "Unknown user", but it could be any reserved '
68 .
'system user (per $wgReservedUsernames) or locally registered user. '
69 .
'If not given, invalid actors will only be listed, not fixed. '
70 .
'You will be prompted for confirmation before data is written. ',
82 $userNameUtils =
null,
86 $services = MediaWikiServices::getInstance();
88 $this->loadBalancer =
$loadBalancer ?? $this->loadBalancer ?? $services->getDBLoadBalancer();
89 $this->lbFactory =
$lbFactory ?? $this->lbFactory ?? $services->getDBLoadBalancerFactory();
102 $name = $this->
getOption(
'overwrite-with' );
104 if ( $name ===
null ) {
108 $user = User::newFromName( $name );
111 $this->
fatalError(
"Not a valid user name: '$user'" );
114 $name = User::getCanonicalName( $name );
116 if ( $user->isRegistered() ) {
117 $this->
output(
"Using existing user: '$user'\n" );
118 } elseif ( !User::isValidUserName( $name ) ) {
119 $this->
fatalError(
"Not a valid user name: '$name'" );
120 } elseif ( !User::isUsableName( $name ) ) {
121 $this->
output(
"Using system user: '$name'\n" );
127 $dbw = $this->loadBalancer->getConnectionRef(
DB_MASTER );
128 $actorId = $user->getActorId( $dbw );
131 $this->
fatalError(
"Failed to acquire an actor ID for user '$user'" );
134 $this->
output(
"Replacement actor ID is $actorId.\n" );
145 if ( !isset( self::TABLES[$field] ) ) {
146 $this->
fatalError(
"Unknown field: $field.\n" );
154 if ( $bad && $overwrite ) {
156 $this->
output(
"Do you want to OVERWRITE the listed actor IDs?\n" );
157 $this->
output(
"Information about the invalid IDs will be lost!\n" );
159 $confirm = $this->
readconsole(
'Type "yes" to continue: ' );
161 if ( $confirm ===
'yes' ) {
168 $this->
output(
"Done.\n" );
180 [ $table, $actorField, $idField ] = self::TABLES[$field];
181 $this->
output(
"Finding invalid actor IDs in $table.$actorField...\n" );
183 $dbr = $this->loadBalancer->getConnectionRef(
185 [
'maintenance',
'vslow',
'slow' ]
204 $conds = [
'actor_id' => null ];
207 $conds[] = $actorField .
' NOT IN ( ' .
$dbr->makeList( $skip ) .
' ) ';
210 $queryBuilder =
$dbr->newSelectQueryBuilder();
211 $queryBuilder->table( $table )
212 ->fields( [ $actorField, $idField ] )
214 ->leftJoin(
'actor',
null, [
"$actorField = actor_id" ] )
216 ->caller( __METHOD__ );
218 $res = $queryBuilder->fetchResultSet();
219 $count =
$res->numRows();
224 $this->
output(
"\t\tID\tACTOR\n" );
227 foreach (
$res as $row ) {
228 $id = $row->$idField;
229 $actor = (int)( $row->$actorField );
232 $this->
output(
"\t\t$id\t$actor\n" );
235 $this->
output(
"\tFound $count invalid actor IDs.\n" );
238 $this->
output(
"\tBatch size reached, run again after fixing the current batch.\n" );
254 [ $table, $actorField, $idField ] = self::TABLES[$field];
256 $count = count( $ids );
257 $this->
output(
"OVERWRITING $count actor IDs in $table.$actorField with $overwrite...\n" );
259 $dbw = $this->loadBalancer->getConnectionRef(
DB_MASTER );
261 $dbw->update( $table, [ $actorField => $overwrite ], [ $idField => $ids ], __METHOD__ );
263 $count = $dbw->affectedRows();
265 $this->lbFactory->waitForReplication();
266 $this->
output(
"\tUpdated $count rows.\n" );
const RUN_MAINTENANCE_IF_MAIN
Maintenance script for finding and replacing invalid actor IDs, see T261325.
initializeServices( $userFactory=null, $userNameUtils=null, ?LoadBalancer $loadBalancer=null, ?LBFactory $lbFactory=null)
The $userFactory and $userNameUtils only exist to prevent the function signature having a breaking ch...
findBadActors( $field, $skip)
Find rows that have bad actor IDs.
execute()
Do the actual work.All child classes will need to implement thisbool|null|void True for success,...
getNewActorId()
Returns the actor ID of the user specified with the –overwrite-with option, or null if –overwrite-wit...
overwriteActorIDs( $field, array $ids, int $overwrite)
Overwrite the actor ID in a given set of rows.
__construct()
Default constructor.
LoadBalancer null $loadBalancer
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
output( $out, $channel=null)
Throw some output to the user.
static readconsole( $prompt='> ')
Prompt the console for input.
getBatchSize()
Returns batch size.
parseIntList( $text)
Utility function to parse a string (perhaps from a command line option) into a list of integers (perh...
addDescription( $text)
Set the description text.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
getOption( $name, $default=null)
Get an option, or return the default.
setBatchSize( $s=0)
Set the batch size.
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.