X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FActorMigration.php;h=597b8e76e79e06bbe0245bea7b3e7deb4e0fac94;hb=d7451a03e98568652ba8b0a1c31034c04d5a7992;hp=51dfa60a0bef2c213e8183cf5efc92a5e8f69abf;hpb=1504dea1127a5f7960dcdc4eed5a044f6a962deb;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/ActorMigration.php b/includes/ActorMigration.php index 51dfa60a0b..597b8e76e7 100644 --- a/includes/ActorMigration.php +++ b/includes/ActorMigration.php @@ -34,6 +34,12 @@ use Wikimedia\Rdbms\IDatabase; */ class ActorMigration { + /** + * Constant for extensions to feature-test whether $wgActorTableSchemaMigrationStage + * expects MIGRATION_* or SCHEMA_COMPAT_* + */ + const MIGRATION_STAGE_SCHEMA_COMPAT = 1; + /** * Define fields that use temporary tables for transitional purposes * @var array Keys are '$key', values are arrays with four fields: @@ -74,11 +80,27 @@ class ActorMigration { /** @var array|null Cache for `self::getJoin()` */ private $joinCache = null; - /** @var int One of the MIGRATION_* constants */ + /** @var int Combination of SCHEMA_COMPAT_* constants */ private $stage; /** @private */ public function __construct( $stage ) { + if ( ( $stage & SCHEMA_COMPAT_WRITE_BOTH ) === 0 ) { + throw new InvalidArgumentException( '$stage must include a write mode' ); + } + if ( ( $stage & SCHEMA_COMPAT_READ_BOTH ) === 0 ) { + throw new InvalidArgumentException( '$stage must include a read mode' ); + } + if ( ( $stage & SCHEMA_COMPAT_READ_BOTH ) === SCHEMA_COMPAT_READ_BOTH ) { + throw new InvalidArgumentException( 'Cannot read both schemas' ); + } + if ( ( $stage & SCHEMA_COMPAT_READ_OLD ) && !( $stage & SCHEMA_COMPAT_WRITE_OLD ) ) { + throw new InvalidArgumentException( 'Cannot read the old schema without also writing it' ); + } + if ( ( $stage & SCHEMA_COMPAT_READ_NEW ) && !( $stage & SCHEMA_COMPAT_WRITE_NEW ) ) { + throw new InvalidArgumentException( 'Cannot read the new schema without also writing it' ); + } + $this->stage = $stage; } @@ -96,7 +118,7 @@ class ActorMigration { * @return string */ public function isAnon( $field ) { - return $this->stage === MIGRATION_NEW ? "$field IS NULL" : "$field = 0"; + return ( $this->stage & SCHEMA_COMPAT_READ_NEW ) ? "$field IS NULL" : "$field = 0"; } /** @@ -105,7 +127,7 @@ class ActorMigration { * @return string */ public function isNotAnon( $field ) { - return $this->stage === MIGRATION_NEW ? "$field IS NOT NULL" : "$field != 0"; + return ( $this->stage & SCHEMA_COMPAT_READ_NEW ) ? "$field IS NOT NULL" : "$field != 0"; } /** @@ -114,11 +136,7 @@ class ActorMigration { * @return string[] [ $text, $actor ] */ private static function getFieldNames( $key ) { - if ( isset( self::$specialFields[$key] ) ) { - return self::$specialFields[$key]; - } - - return [ $key . '_text', substr( $key, 0, -5 ) . '_actor' ]; + return self::$specialFields[$key] ?? [ $key . '_text', substr( $key, 0, -5 ) . '_actor' ]; } /** @@ -140,18 +158,16 @@ class ActorMigration { list( $text, $actor ) = self::getFieldNames( $key ); - if ( $this->stage === MIGRATION_OLD ) { + if ( $this->stage & SCHEMA_COMPAT_READ_OLD ) { $fields[$key] = $key; $fields[$text] = $text; $fields[$actor] = 'NULL'; } else { - $join = $this->stage === MIGRATION_NEW ? 'JOIN' : 'LEFT JOIN'; - if ( isset( self::$tempTables[$key] ) ) { $t = self::$tempTables[$key]; $alias = "temp_$key"; $tables[$alias] = $t['table']; - $joins[$alias] = [ $join, "{$alias}.{$t['pk']} = {$t['joinPK']}" ]; + $joins[$alias] = [ 'JOIN', "{$alias}.{$t['pk']} = {$t['joinPK']}" ]; $joinField = "{$alias}.{$t['field']}"; } else { $joinField = $actor; @@ -159,15 +175,10 @@ class ActorMigration { $alias = "actor_$key"; $tables[$alias] = 'actor'; - $joins[$alias] = [ $join, "{$alias}.actor_id = {$joinField}" ]; + $joins[$alias] = [ 'JOIN', "{$alias}.actor_id = {$joinField}" ]; - if ( $this->stage === MIGRATION_NEW ) { - $fields[$key] = "{$alias}.actor_user"; - $fields[$text] = "{$alias}.actor_name"; - } else { - $fields[$key] = "COALESCE( {$alias}.actor_user, $key )"; - $fields[$text] = "COALESCE( {$alias}.actor_name, $text )"; - } + $fields[$key] = "{$alias}.actor_user"; + $fields[$text] = "{$alias}.actor_name"; $fields[$actor] = $joinField; } @@ -197,11 +208,11 @@ class ActorMigration { list( $text, $actor ) = self::getFieldNames( $key ); $ret = []; - if ( $this->stage <= MIGRATION_WRITE_BOTH ) { + if ( $this->stage & SCHEMA_COMPAT_WRITE_OLD ) { $ret[$key] = $user->getId(); $ret[$text] = $user->getName(); } - if ( $this->stage >= MIGRATION_WRITE_BOTH ) { + if ( $this->stage & SCHEMA_COMPAT_WRITE_NEW ) { // We need to be able to assign an actor ID if none exists if ( !$user instanceof User && !$user->getActorId() ) { $user = User::newFromAnyId( $user->getId(), $user->getName(), null ); @@ -233,11 +244,11 @@ class ActorMigration { list( $text, $actor ) = self::getFieldNames( $key ); $ret = []; $callback = null; - if ( $this->stage <= MIGRATION_WRITE_BOTH ) { + if ( $this->stage & SCHEMA_COMPAT_WRITE_OLD ) { $ret[$key] = $user->getId(); $ret[$text] = $user->getName(); } - if ( $this->stage >= MIGRATION_WRITE_BOTH ) { + if ( $this->stage & SCHEMA_COMPAT_WRITE_NEW ) { // We need to be able to assign an actor ID if none exists if ( !$user instanceof User && !$user->getActorId() ) { $user = User::newFromAnyId( $user->getId(), $user->getName(), null ); @@ -301,6 +312,8 @@ class ActorMigration { * - orconds: (array[]) array of alternatives in case a union of multiple * queries would be more efficient than a query with OR. May have keys * 'actor', 'userid', 'username'. + * Since 1.32, this is guaranteed to contain just one alternative if + * $users contains a single user. * - joins: (array) to include in the `$join_conds` to `IDatabase->select()` * All tables and joins are aliased, so `+` is safe to use. */ @@ -332,44 +345,26 @@ class ActorMigration { list( $text, $actor ) = self::getFieldNames( $key ); // Combine data into conditions to be ORed together - $actorNotEmpty = []; - if ( $this->stage === MIGRATION_OLD ) { - $actors = []; - $actorEmpty = []; - } elseif ( isset( self::$tempTables[$key] ) ) { - $t = self::$tempTables[$key]; - $alias = "temp_$key"; - $tables[$alias] = $t['table']; - $joins[$alias] = [ - $this->stage === MIGRATION_NEW ? 'JOIN' : 'LEFT JOIN', - "{$alias}.{$t['pk']} = {$t['joinPK']}" - ]; - $joinField = "{$alias}.{$t['field']}"; - $actorEmpty = [ $joinField => null ]; - if ( $this->stage !== MIGRATION_NEW ) { - // Otherwise the resulting test can evaluate to NULL, and - // NOT(NULL) is NULL rather than true. - $actorNotEmpty = [ "$joinField IS NOT NULL" ]; + if ( $this->stage & SCHEMA_COMPAT_READ_NEW ) { + if ( $actors ) { + if ( isset( self::$tempTables[$key] ) ) { + $t = self::$tempTables[$key]; + $alias = "temp_$key"; + $tables[$alias] = $t['table']; + $joins[$alias] = [ 'JOIN', "{$alias}.{$t['pk']} = {$t['joinPK']}" ]; + $joinField = "{$alias}.{$t['field']}"; + } else { + $joinField = $actor; + } + $conds['actor'] = $db->makeList( [ $joinField => $actors ], IDatabase::LIST_AND ); } } else { - $joinField = $actor; - $actorEmpty = [ $joinField => 0 ]; - } - - if ( $actors ) { - $conds['actor'] = $db->makeList( - $actorNotEmpty + [ $joinField => $actors ], IDatabase::LIST_AND - ); - } - if ( $this->stage < MIGRATION_NEW && $ids ) { - $conds['userid'] = $db->makeList( - $actorEmpty + [ $key => $ids ], IDatabase::LIST_AND - ); - } - if ( $this->stage < MIGRATION_NEW && $names ) { - $conds['username'] = $db->makeList( - $actorEmpty + [ $text => $names ], IDatabase::LIST_AND - ); + if ( $ids ) { + $conds['userid'] = $db->makeList( [ $key => $ids ], IDatabase::LIST_AND ); + } + if ( $names ) { + $conds['username'] = $db->makeList( [ $text => $names ], IDatabase::LIST_AND ); + } } return [