如何在测试 laravel 中更改迁移中的枚举类型列

Posted

技术标签:

【中文标题】如何在测试 laravel 中更改迁移中的枚举类型列【英文标题】:how to alter enum type column in migration in testing laravel 【发布时间】:2020-11-22 08:42:26 【问题描述】:

假设我有一个在生产环境中运行的代码,因此,我无法更改相同的迁移文件以添加新列,如下所示

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    
        Schema::create('users', function (Blueprint $table) 
            $table->bigIncrements('id');
            $table->string('name')->nullable();
            $table->string('email')->unique();
            $table->string('token_key')->unique()->nullable();
            $table->enum('type', ['avatar', 'image', 'video'])->comment(implode(', ', ['avatar', 'image', 'video']));
            $table->timestamps();
        );
    

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    
        Schema::dropIfExists('users');
    

在第一个版本之后,我想从名为 type 可接受值的列中删除 avatar 值,所以我添加了一个新的迁移文件来添加我的新列,如下所示

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ChangeEnumOnUsersTable extends Migration

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    
        $sql = sprintf(
            "ALTER TABLE %s CHANGE `%s` `%s` ENUM('%s') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '%s'",
            'users',
            'type',
            'type',
            implode('\',\'', ['image', 'video']),
            implode(',', ['image', 'video'])
        );
        DB::statement($sql);
    

并使用vendor/bin/phpunit 我运行我的测试

请注意,首先数据库将被迁移,并且由于该测试方法没有启动

SQLite 抛出如下错误。

SQLite 异常是这样的

PDOException: SQLSTATE[HY000]: General error: 1 near "CHANGE": syntax error

Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1 near "CHANGE": syntax error (SQL: ALTER TABLE users CHANGE `type` `type` ENUM('image','video') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'image,video')

【问题讨论】:

您好,欢迎来到 SO。如果没有详细信息,这将是一个很难解决的问题。添加第二次迁移的内容将是一个很好的输入。你有什么尝试让它发挥作用。 【参考方案1】:

您不得使用DB::statementsprintf 修改您的字段。

所以你可以像这样使用 Laravel 迁移机制的内置函数change

Schema::table('users', function (Blueprint $table) 
    $table->string('name', 50)->change(); // update the field by increasing the max allowed characters
);

请参阅:Laravel Migration: Modifying Columns

【讨论】:

【参考方案2】:

我已经搜索并找到了这个解决方案,希望有用。

我的问题是数据库的行为和对键的支持,当您使用 laravel 的迁移功能来更改 enum 类型时,您必须首先将 doctrine/dbal 包添加到您的项目中

 composer require doctrine/dbal

那么您必须将enum 类型添加到学说中,因为 laravel 正在使用该包来操作表列,并且此 laravel 默认情况下没有将enum 类型添加到学说中,因此您需要更改迁移中的 __construct 方法,如下所示

use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Types\StringType;

public function __construct()

    if (! Type::hasType('enum')) 
        Type::addType('enum', StringType::class);
    
    DB::getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');

然后您可以更改您的enum 列,如下所示

$table->enum('type', ['avatar', 'video'])
      ->comment(implode(', ', ['avatar', 'video']))
      ->change();

并且知道在测试中更改枚举类型字段没有问题。

注意: 此解决方案是doctrine project's site 上的ENUM 类型提供的解决方案之一,它提供两种解决方案,第一个是Mapping to varchars,第二个是Defining a custom type for enum

如果上述解决方案对您不起作用,那么您可以在doctrine project's siteyourself 中阅读有关此问题以及如何解决它的更多信息

【讨论】:

这不起作用 - 迁移将成功运行,但您的列(根据我的经验)从枚举转换为 varchar。这不是预期的行为 @sudoyum 感谢您的评论,我确实添加了学说项目的站点以获得更多解决方案,该站点清楚地说明了问题和解决方案,我希望这个解决方案对您有用

以上是关于如何在测试 laravel 中更改迁移中的枚举类型列的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Laravel 的选择选项中使用“枚举”值?

在 Laravel 迁移中更改列类型的最佳方法是啥?

Laravel db 迁移 - renameColumn 错误 - 请求了未知的数据库类型枚举

如何修复laravel迁移中的外键错误

如何使用 laravel 迁移和种子正确处理数据库数据更改

如何使用 Laravel 迁移将字符串列类型转换为整数?