Laravel迁移数组类型(在数据库列中存储数组)

57

我想在我的表中存储一个整数数组,但我找不到任何支持数组的类型在文档中,有什么建议。

迁移:

public function up()
{
    Schema::create('pickups', function (Blueprint $table) {
        $table->increment('id');
        $table->boolean('default');
        $table->integer('shifts');  <<--------- HERE I want to store an array of integers
        $table->integer('status_id');

        $table->timestamps();
    });
}
5个回答

113

array 数据类型并不是所有数据库系统都支持的,因为 Laravel 的 Schema Builder 是数据库无关的,所以它没有提供创建非通用数据类型列的方法。因此你有两个选择:

1. 使用原始 SQL 语句添加该列,类似下面的语句应该可以工作。虽然我不确定 Query Builder 或 Eloquent 是否可以正确处理这些类型的列:

DB::statement('ALTER TABLE pickups ADD COLUMN shifts integer[]');

2. 使用Eloquent提供的可用解决方案,使用属性转换。在您的迁移中创建列,如下所示:json

public function up()
{
    Schema::create('pickups', function (Blueprint $table) {
        $table->increment('id');
        $table->boolean('default');
        $table->json('shifts');
        $table->integer('status_id');

        $table->timestamps();
    });
}

然后您可以设置您的Pickup模型(如果您还没有这样做)并使用$casts属性:

class Pickup extends Model
{
    protected $casts = [
        'shifts' => 'array'
    ];
}

这将让Eloquent知道,当它从数据库中获取数据时,它将不得不将shifts列值转换为一个array。这只是模拟了一个实际的数组,因为在数据库层面上,该列的类型为TEXT,而数组被序列化了。然而,当反序列化列值时,Eloquent会返回一个实际的整数数组供您在代码中使用。以下是一个示例用例:

// Create a new Pickup entry
$pickup = App\Pickup::create([
    'default' => true,
    'shifts' => '[1, 5, 7]', // you can easily assign an actual integer array here
    'status_id' => 1
]);

假设上述操作生成了一个具有id等于1的条目,当您稍后检索该条目时:
$pickup = App\Pickup::find(1);
dump($pickup->shifts);

上述代码中的dump()将输出一个实际的整数数组:

array:3 [▼
  0 => 1
  1 => 5
  2 => 7
]

感谢@Bogdan提供的出色答案,但是当我尝试使用'shifts' => [1, 5, 7]创建新的接送条目时,我收到了以下错误消息:PHP warning: preg_replace(): Parameter mismatch, pattern is a string while replacement is an array - Zakaria Acharki
好的,现在它的工作方式如下:'shifts' => '[1, 5, 7]',谢谢 :) - Zakaria Acharki
1
我已经在全新安装的 Laravel 5.1 上进行了测试,在为变量赋值时,实际上不需要在数组周围加引号,它可以正常工作。 - Bogdan
2
在这种情况下,查询是否可行?例如,我想要包含第5个班次的所有记录。 - Marin Leontenko
是的,@MarinLeontenko,查询是个难点。我能够轻松地在postgresql中创建一个JSON列并在模型中强制转换为数组,你也可以轻松地获取数据,但到目前为止,我还没有找到一种成功完成您要求的方法。 - Fred Polli

7

还有一种更复杂的方法,但它可以使用模式生成器创建真正的本地数组。

以PostgreSQL为例。

  1. 注册新的int_array类型,通过扩展现有的DB模式语法将其解析为int[]
\DB::connection()->setSchemaGrammar(new class extends PostgresGrammar {
    protected function typeInt_array(\Illuminate\Support\Fluent $column)
    {
        return 'int[]';
    }
});

如果您只需要使用一次,则可以将此代码直接放在迁移中,或者放入 AppServiceProvider 中使其在整个项目中可用。

  1. 现在您可以在迁移中使用此类型:
Schema::table('users', function (Blueprint $table) {
    $table->addColumn('int_array', 'group_ids')->nullable();
});

谢谢。我最喜欢这个 :) 上帝保佑! - Lachezar Raychev

2

通常我会将数组存储在一个以逗号分隔的字符串列中,并使用explode检索它。

因此,在您的情况下,当进行存储时,我会做如下操作:

$arraystring = implode(',',$array);

$pickups->shifts = $arraystring; //$pickups is an instance of your Pickups model.

//Then while retrieving I would just use;

$array = $pickups->shifts ? explode(',',$pickups-shifts) : []; 
/*just to make sure it is not an empty string 
else you will get an error on explode.*/

0

简单地,使用 JSON 存储整数数组:

$table->json('shifts');

0
你可以简单地添加:
protected $cast=['shifts'=>'array'];

在你的模型类中,它在 Laravel 8 中对我有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接