25use InvalidArgumentException;
40 private $joinCache = [];
53 private bool $allowUnknown;
104 $this->fieldInfos = $fieldInfos;
105 $this->allowUnknown = $options[
'allowUnknown'] ??
true;
109 if ( $writeStage === 0 ) {
110 throw new InvalidArgumentException(
'$stage must include a write mode' );
112 if ( $readStage === 0 ) {
113 throw new InvalidArgumentException(
'$stage must include a read mode' );
118 throw new InvalidArgumentException(
'Cannot read multiple schemas' );
121 throw new InvalidArgumentException(
'Cannot read the old schema without also writing it' );
124 throw new InvalidArgumentException(
'Cannot read the temp schema without also writing it' );
127 throw new InvalidArgumentException(
'Cannot read the new schema without also writing it' );
129 $this->readStage = $readStage;
130 $this->writeStage = $writeStage;
132 $this->actorStoreFactory = $actorStoreFactory;
144 if ( isset( $this->fieldInfos[$key] ) ) {
145 return $this->fieldInfos[$key];
146 } elseif ( $this->allowUnknown ) {
149 throw new InvalidArgumentException( $this->
getInstanceName() .
": unknown key $key" );
162 if ( (
new ReflectionClass( $this ) )->isAnonymous() ) {
166 return static::class;
179 if ( isset( $fieldInfo[
'removedVersion'] ) ) {
180 $removedVersion = $fieldInfo[
'removedVersion'];
181 $component = $fieldInfo[
'component'] ??
'MediaWiki';
182 throw new InvalidArgumentException(
183 "Use of {$this->getInstanceName()} for '$key' was removed in $component $removedVersion"
186 if ( isset( $fieldInfo[
'deprecatedVersion'] ) ) {
187 $deprecatedVersion = $fieldInfo[
'deprecatedVersion'];
188 $component = $fieldInfo[
'component'] ??
'MediaWiki';
189 wfDeprecated(
"{$this->getInstanceName()} for '$key'", $deprecatedVersion, $component, 3 );
216 private function getFieldNames( $key ) {
218 $textField = $fieldInfo[
'textField'] ?? $key .
'_text';
219 $actorField = $fieldInfo[
'actorField'] ?? substr( $key, 0, -5 ) .
'_actor';
220 return [ $textField, $actorField ];
229 private function getTempTableInfo( $key ) {
231 return $fieldInfo[
'tempTable'] ??
null;
249 if ( !isset( $this->joinCache[$key] ) ) {
254 [ $text, $actor ] = $this->getFieldNames( $key );
257 $fields[$key] = $key;
258 $fields[$text] = $text;
259 $fields[$actor] =
'NULL';
261 $tempTableInfo = $this->getTempTableInfo( $key );
262 if ( $tempTableInfo ) {
263 $alias =
"temp_$key";
264 $tables[$alias] = $tempTableInfo[
'table'];
267 "{$alias}.{$tempTableInfo['pk']} = {$tempTableInfo['joinPK']}",
269 $joinField =
"{$alias}.{$tempTableInfo['field']}";
274 $alias =
"actor_$key";
275 $tables[$alias] =
'actor';
276 $joins[$alias] = [
'JOIN',
"{$alias}.actor_id = {$joinField}" ];
278 $fields[$key] =
"{$alias}.actor_user";
279 $fields[$text] =
"{$alias}.actor_name";
280 $fields[$actor] = $joinField;
282 $alias =
"actor_$key";
283 $tables[$alias] =
'actor';
284 $joins[$alias] = [
'JOIN',
"{$alias}.actor_id = {$actor}" ];
286 $fields[$key] =
"{$alias}.actor_user";
287 $fields[$text] =
"{$alias}.actor_name";
288 $fields[$actor] = $actor;
291 $this->joinCache[$key] = [
298 return $this->joinCache[$key];
313 if ( $this->getTempTableInfo( $key ) ) {
314 throw new InvalidArgumentException(
"Must use getInsertValuesWithTempTable() for $key" );
317 [ $text, $actor ] = $this->getFieldNames( $key );
320 $ret[$key] = $user->
getId();
321 $ret[$text] = $user->
getName();
325 $this->actorStoreFactory->getActorNormalization( $dbw->
getDomainID() )->acquireActorId( $user, $dbw );
346 $tempTableInfo = $fieldInfo[
'tempTable'] ??
null;
347 if ( isset( $fieldInfo[
'formerTempTableVersion'] ) ) {
349 __METHOD__ .
" for $key",
350 $fieldInfo[
'formerTempTableVersion'],
351 $fieldInfo[
'component'] ??
'MediaWiki'
353 } elseif ( !$tempTableInfo ) {
354 throw new InvalidArgumentException(
"Must use getInsertValues() for $key" );
357 [ $text, $actor ] = $this->getFieldNames( $key );
362 $ret[$key] = $user->
getId();
363 $ret[$text] = $user->
getName();
366 $id = $this->actorStoreFactory
368 ->acquireActorId( $user, $dbw );
370 if ( $tempTableInfo ) {
373 $callback =
static function ( $pk, array $extra ) use ( $tempTableInfo, $dbw, $id, $func ) {
374 $set = [ $tempTableInfo[
'field'] => $id ];
375 foreach ( $tempTableInfo[
'extra'] as $to => $from ) {
376 if ( !array_key_exists( $from, $extra ) ) {
377 throw new InvalidArgumentException(
"$func callback: \$extra[$from] is not provided" );
379 $set[$to] = $extra[$from];
382 ->insertInto( $tempTableInfo[
'table'] )
383 ->row( [ $tempTableInfo[
'pk'] => $pk ] + $set )
384 ->onDuplicateKeyUpdate()
385 ->uniqueIndexFields( [ $tempTableInfo[
'pk'] ] )
387 ->caller( $func )->execute();
398 if ( $callback ===
null ) {
400 if ( $tempTableInfo ) {
402 $callback =
static function ( $pk, array $extra ) use ( $tempTableInfo, $func ) {
403 foreach ( $tempTableInfo[
'extra'] as $from ) {
404 if ( !array_key_exists( $from, $extra ) ) {
405 throw new InvalidArgumentException(
"$func callback: \$extra[$from] is not provided" );
410 $callback =
static function ( $pk, array $extra ) {
414 return [ $ret, $callback ];
450 } elseif ( $users ===
null || $users ===
false ) {
453 } elseif ( !is_array( $users ) ) {
454 $what = is_object( $users ) ? get_class( $users ) : gettype( $users );
455 throw new InvalidArgumentException(
456 __METHOD__ .
": Value for \$users must be a UserIdentity or array, got $what"
464 foreach ( $users as $user ) {
465 if ( $useId && $user->isRegistered() ) {
466 $ids[] = $user->getId();
469 $names[] = IPUtils::sanitizeIP( $user->getName() );
471 $actorId = $this->actorStoreFactory
473 ->findActorId( $user, $db );
476 $actors[] = $actorId;
480 [ $text, $actor ] = $this->getFieldNames( $key );
485 $conds[
'newactor'] = $db->
makeList( [ $actor => $actors ], IDatabase::LIST_AND );
489 $tempTableInfo = $this->getTempTableInfo( $key );
490 if ( $tempTableInfo ) {
491 $alias =
"temp_$key";
492 $tables[$alias] = $tempTableInfo[
'table'];
495 "{$alias}.{$tempTableInfo['pk']} = {$tempTableInfo['joinPK']}",
497 $joinField =
"{$alias}.{$tempTableInfo['field']}";
501 $conds[
'actor'] = $db->
makeList( [ $joinField => $actors ], IDatabase::LIST_AND );
505 $conds[
'userid'] = $db->
makeList( [ $key => $ids ], IDatabase::LIST_AND );
508 $conds[
'username'] = $db->
makeList( [ $text => $names ], IDatabase::LIST_AND );
514 'conds' => $conds ? $db->
makeList( array_values( $conds ), IDatabase::LIST_OR ) :
'1=0',
524class_alias( ActorMigrationBase::class,
'ActorMigrationBase' );
const SCHEMA_COMPAT_WRITE_TEMP
const SCHEMA_COMPAT_READ_NEW
const SCHEMA_COMPAT_WRITE_OLD
const SCHEMA_COMPAT_READ_TEMP
const SCHEMA_COMPAT_READ_OLD
const SCHEMA_COMPAT_WRITE_NEW
const SCHEMA_COMPAT_WRITE_MASK
const SCHEMA_COMPAT_READ_MASK
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.