Doctrine DBAL, команда diff и тип перечисления

#php #symfony #doctrine-migrations #doctrine-dbal

#php #symfony #доктрина-миграции #doctrine-dbal

Вопрос:

Я работаю с symfony 5.1, doctrine-bundle 2.1.2 и doctrine-migrations-bundle 2.2. Я НЕ работаю с ORM и определяю свои собственные схемы. Чтобы добавить типы перечислений, я использую следующий код:

 abstract class EnumType extends Type
{
    protected string $name;

    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
    {
        $values = $this->getValues();
        $maxLength = max(array_map('strlen', $values));
        $columnName = $fieldDeclaration['name'];

        $implodedValues = implode(', ', array_map(function($value) {return "'$value'";}, $values));

        if ($platform instanceof MySqlPlatform) {
            return "ENUM($implodedValues)";
        }

        if (
            $platform instanceof SQLServer2012Platform
            || $platform instanceof PostgreSQL94Platform
        ) {
            return "VARCHAR($maxLength) CHECK ({$columnName} IN ($implodedValues))";
        }

        if ($platform instanceof SqlitePlatform) {
            return "TEXT CHECK ({$columnName} IN ($implodedValues))";
        }

        throw DBALException::invalidPlatformType($platform);
    }

    public function convertToPHPValue($value, AbstractPlatform $platform)
    {
        return $value;
    }

    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        if (!in_array($value, $this->getValues())) {
            throw new InvalidArgumentException("Invalid '" . $this->name . "' value: " . (string)$value);
        }
        return $value;
    }

    public function getName()
    {
        return $this->name;
    }

    public function requiresSQLCommentHint(AbstractPlatform $platform)
    {
        return true;
    }

    abstract function getValues(): array;
}
  

Затем каждое перечисление расширяет этот абстрактный класс для установки значений.

Создание не проблема. Когда я запускаю команду migration diff, я получаю следующее сообщение об ошибке:

Запрошен неизвестный тип базы данных enum, Doctrine DBAL Platforms MySQL57Platform может не поддерживать его.

Есть идеи, как я могу создать diff, который также включает любые изменения в самом enum?

Ответ №1:

Я решил это, создав свой собственный diff, который сначала добавляет тип ‘enum’, если он еще не существует, используя:

 if ($connection->getDatabasePlatform() instanceof MySqlPlatform) {
    if (!Type::hasType('enum')) {
        Type::addType('enum', StringType::class);
    }
    $connection->getDatabasePlatform()->registerDoctrineTypeMapping('enum', Types::STRING);
}
  

После этого я пытаюсь прочитать все доступные таблицы и перехватить любое исключение для типа, который не определен, определить его как строку, а затем повторить попытку:

 $schemaManager = $this->connection->getSchemaManager();
do {
    try {
        return new Schema($schemaManager->listTables(), [], $schemaManager->createSchemaConfig());
    } catch (Exception $exception) {
        $hasErrors = true;
        $message = $exception->getMessage();
        $parts = explode('"', $message);
        // convert any removed custom type to string
        Type::addType($parts[1], StringType::class);
    }
} while ($hasErrors);
  

Это вернет текущую схему БД. Из которого можно создать diff с новой схемой.