diff --git a/CHANGELOG.md b/CHANGELOG.md index e11cbd3e4..155d1ce9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,7 +35,7 @@ - Enh #865: Raise minimum PHP version to `^8.1` with minor refactoring (@Tigrov, @vjik) - Enh #798: Allow `QueryInterface::one()` and `QueryInterface::all()` to return objects (@darkdef, @Tigrov) - Enh #872: Use `#[\SensitiveParameter]` attribute to mark sensitive parameters (@heap-s) -- New #864: Realize column factory (@Tigrov) +- New #864, #897: Realize column factory (@Tigrov) - Enh #875: Ignore "Packets out of order..." warnings in `AbstractPdoCommand::internalExecute()` method (@Tigrov) - Enh #877: Separate column type constants (@Tigrov) - Enh #878: Realize `ColumnBuilder` class (@Tigrov) diff --git a/src/Schema/Column/AbstractColumnFactory.php b/src/Schema/Column/AbstractColumnFactory.php index a58789c1c..4fc4627bb 100644 --- a/src/Schema/Column/AbstractColumnFactory.php +++ b/src/Schema/Column/AbstractColumnFactory.php @@ -18,29 +18,18 @@ abstract class AbstractColumnFactory implements ColumnFactoryInterface { /** - * Get the abstract database type for a database column type. - * - * @param string $dbType The database column type. - * @param array $info The column information. + * The mapping from physical column types (keys) to abstract column types (values). * - * @return string The abstract database type. + * @var string[] * - * @psalm-param ColumnInfo $info - * @psalm-return ColumnType::* + * @psalm-var array */ - abstract protected function getType(string $dbType, array $info = []): string; - - /** - * Checks if the column type is a database type. - */ - abstract protected function isDbType(string $dbType): bool; + protected const TYPE_MAP = []; public function fromDbType(string $dbType, array $info = []): ColumnSchemaInterface { - unset($info['dbType']); - $type = $info['type'] ?? $this->getType($dbType, $info); - unset($info['type']); $info['dbType'] = $dbType; + $type = $info['type'] ?? $this->getType($dbType, $info); return $this->fromType($type, $info); } @@ -60,12 +49,10 @@ public function fromDefinition(string $definition, array $info = []): ColumnSche $info += $definitionInfo; if ($this->isDbType($type)) { - unset($info['dbType']); return $this->fromDbType($type, $info); } if ($this->isType($type)) { - unset($info['type']); return $this->fromType($type, $info); } @@ -73,64 +60,103 @@ public function fromDefinition(string $definition, array $info = []): ColumnSche return $this->fromPseudoType($type, $info); } - unset($info['dbType']); return $this->fromDbType($type, $info); } - /** - * @psalm-suppress MixedArgument - * @psalm-suppress InvalidArgument - * @psalm-suppress InvalidNamedArgument - */ public function fromPseudoType(string $pseudoType, array $info = []): ColumnSchemaInterface { $info['primaryKey'] = true; $info['autoIncrement'] = true; - return match ($pseudoType) { - PseudoType::PK => new IntegerColumnSchema(ColumnType::INTEGER, ...$info), - PseudoType::UPK => new IntegerColumnSchema(ColumnType::INTEGER, ...[...$info, 'unsigned' => true]), - PseudoType::BIGPK => PHP_INT_SIZE !== 8 - ? new BigIntColumnSchema(ColumnType::BIGINT, ...$info) - : new IntegerColumnSchema(ColumnType::BIGINT, ...$info), - PseudoType::UBIGPK => new BigIntColumnSchema(ColumnType::BIGINT, ...[...$info, 'unsigned' => true]), - PseudoType::UUID_PK => new StringColumnSchema(ColumnType::UUID, ...$info), - PseudoType::UUID_PK_SEQ => new StringColumnSchema(ColumnType::UUID, ...$info), + if ($pseudoType === PseudoType::UPK || $pseudoType === PseudoType::UBIGPK) { + $info['unsigned'] = true; + } + + $type = match ($pseudoType) { + PseudoType::PK => ColumnType::INTEGER, + PseudoType::UPK => ColumnType::INTEGER, + PseudoType::BIGPK => ColumnType::BIGINT, + PseudoType::UBIGPK => ColumnType::BIGINT, + PseudoType::UUID_PK => ColumnType::UUID, + PseudoType::UUID_PK_SEQ => ColumnType::UUID, }; + + return $this->fromType($type, $info); + } + + public function fromType(string $type, array $info = []): ColumnSchemaInterface + { + unset($info['type']); + + if ($type === ColumnType::ARRAY && empty($info['column']) && !empty($info['dbType'])) { + $info['column'] = $this->fromDbType($info['dbType'], $info); + } + + $columnClass = $this->getColumnClass($type, $info); + + return new $columnClass($type, ...$info); } /** - * @psalm-suppress InvalidNamedArgument + * Returns the column definition parser. */ - public function fromType(string $type, array $info = []): ColumnSchemaInterface + protected function columnDefinitionParser(): ColumnDefinitionParser + { + return new ColumnDefinitionParser(); + } + + /** + * @psalm-param ColumnType::* $type + * @param ColumnInfo $info + * + * @psalm-return class-string + */ + protected function getColumnClass(string $type, array $info = []): string { return match ($type) { - ColumnType::BOOLEAN => new BooleanColumnSchema($type, ...$info), - ColumnType::BIT => new BitColumnSchema($type, ...$info), - ColumnType::TINYINT => new IntegerColumnSchema($type, ...$info), - ColumnType::SMALLINT => new IntegerColumnSchema($type, ...$info), + ColumnType::BOOLEAN => BooleanColumnSchema::class, + ColumnType::BIT => BitColumnSchema::class, + ColumnType::TINYINT => IntegerColumnSchema::class, + ColumnType::SMALLINT => IntegerColumnSchema::class, ColumnType::INTEGER => PHP_INT_SIZE !== 8 && !empty($info['unsigned']) - ? new BigIntColumnSchema($type, ...$info) - : new IntegerColumnSchema($type, ...$info), + ? BigIntColumnSchema::class + : IntegerColumnSchema::class, ColumnType::BIGINT => PHP_INT_SIZE !== 8 || !empty($info['unsigned']) - ? new BigIntColumnSchema($type, ...$info) - : new IntegerColumnSchema($type, ...$info), - ColumnType::DECIMAL => new DoubleColumnSchema($type, ...$info), - ColumnType::FLOAT => new DoubleColumnSchema($type, ...$info), - ColumnType::DOUBLE => new DoubleColumnSchema($type, ...$info), - ColumnType::BINARY => new BinaryColumnSchema($type, ...$info), - ColumnType::STRUCTURED => new StructuredColumnSchema($type, ...$info), - ColumnType::JSON => new JsonColumnSchema($type, ...$info), - default => new StringColumnSchema($type, ...$info), + ? BigIntColumnSchema::class + : IntegerColumnSchema::class, + ColumnType::DECIMAL => DoubleColumnSchema::class, + ColumnType::FLOAT => DoubleColumnSchema::class, + ColumnType::DOUBLE => DoubleColumnSchema::class, + ColumnType::BINARY => BinaryColumnSchema::class, + ColumnType::ARRAY => ArrayColumnSchema::class, + ColumnType::STRUCTURED => StructuredColumnSchema::class, + ColumnType::JSON => JsonColumnSchema::class, + default => StringColumnSchema::class, }; } /** - * Returns the column definition parser. + * Get the abstract database type for a database column type. + * + * @param string $dbType The database column type. + * @param array $info The column information. + * + * @return string The abstract database type. + * + * @psalm-param ColumnInfo $info + * @psalm-return ColumnType::* */ - protected function columnDefinitionParser(): ColumnDefinitionParser + protected function getType(string $dbType, array $info = []): string { - return new ColumnDefinitionParser(); + return static::TYPE_MAP[$dbType] ?? ColumnType::STRING; + } + + /** + * Checks if the column type is a database type. + */ + protected function isDbType(string $dbType): bool + { + return isset(static::TYPE_MAP[$dbType]); } /** diff --git a/tests/Common/CommonSchemaTest.php b/tests/Common/CommonSchemaTest.php index 3f2ffd6fe..bbf5447da 100644 --- a/tests/Common/CommonSchemaTest.php +++ b/tests/Common/CommonSchemaTest.php @@ -359,39 +359,6 @@ public function testGetSchemaUniques(): void $db->close(); } - /** - * @dataProvider \Yiisoft\Db\Tests\Provider\SchemaProvider::columnsTypeChar - */ - public function testGetStringFieldsSize( - string $columnName, - string $columnType, - int|null $columnSize, - string $columnDbType - ): void { - $db = $this->getConnection(true); - - $schema = $db->getSchema(); - $tableSchema = $schema->getTableSchema('type'); - - $this->assertInstanceOf(TableSchemaInterface::class, $tableSchema); - - $columns = $tableSchema->getColumns(); - - foreach ($columns as $name => $column) { - $type = $column->getType(); - $size = $column->getSize(); - $dbType = $column->getDbType(); - - if ($name === $columnName) { - $this->assertSame($columnType, $type); - $this->assertSame($columnSize, $size); - $this->assertSame($columnDbType, $dbType); - } - } - - $db->close(); - } - public function testGetTableChecks(): void { $db = $this->getConnection(true); diff --git a/tests/Provider/SchemaProvider.php b/tests/Provider/SchemaProvider.php index 1cce996fc..bd451a4d1 100644 --- a/tests/Provider/SchemaProvider.php +++ b/tests/Provider/SchemaProvider.php @@ -19,15 +19,6 @@ public static function columns(): array return []; } - public static function columnsTypeChar(): array - { - return [ - ['char_col', 'char', 100, 'char(100)'], - ['char_col2', 'string', 100, 'varchar(100)'], - ['char_col3', 'text', null, 'text'], - ]; - } - public static function constraints(): array { return [