Laravel Backpack Repeater字段无法存储多对多关联至中间表问题
解决多对多关联下商品颜色库存的存储问题
问题背景
商品表(products_table)与颜色表(colors_table)为多对多关系,通过中间表colorables_table关联,需要在中间表存储product_id、color_id以及对应颜色的库存数量number。使用Backpack的Repeater字段配置后,数据未写入中间表,而是以JSON形式存入了products_table的colors字段。
解决步骤
1. 确保中间表包含库存字段
如果colorables_table尚未添加number字段,先创建迁移添加:
Schema::table('colorables', function (Blueprint $table) { $table->integer('number')->default(0)->comment('对应颜色的库存数量'); });
2. 修改Product模型的多对多关联
更新模型中的关联定义,指定携带中间表的number字段:
use Illuminate\Database\Eloquent\Relations\BelongsToMany; public function colors(): BelongsToMany { return $this->belongsToMany(Color::class, 'colorables', 'product_id', 'color_id') ->withPivot('number') // 声明需要读取中间表的number字段 ->withTimestamps(); // 可选,若中间表有created_at/updated_at则添加 }
3. 调整CRUD字段配置
将Repeater字段名改为color_inventories(避免与关联名冲突),并把颜色选择器的name设为color_id,直接获取颜色ID:
CRUD::field('color_inventories')->label('颜色库存')->type('repeatable')->new_item_label('添加库存信息')->fields([ [ 'name' => 'color_id', 'label' => '颜色', 'type' => 'select', 'model' => 'App\Models\Color', 'attribute' => 'name', 'wrapper' => ['class' => 'form-group col-md-6 required'], ], [ 'name' => 'number', 'type' => 'number', 'label' => '库存数量', 'wrapper' => ['class' => 'form-group col-md-6 required'], ], ]);
4. 添加模型访问器(用于编辑页面回显数据)
在Product模型中添加访问器,将已关联的颜色库存数据转换为Repeater字段需要的格式:
public function getColorInventoriesAttribute() { return $this->colors->map(function ($color) { return [ 'color_id' => $color->id, 'number' => $color->pivot->number, ]; })->toArray(); }
5. 处理保存/更新时的数据同步
在CRUD的创建和更新操作中添加保存回调,将Repeater提交的数据同步到中间表,并移除字段避免存入商品表:
在setupCreateOperation()中添加:
$this->crud->addSaveAction([ 'name' => 'save_color_inventory', 'redirect' => function ($crud, $request, $itemId) { return $crud->route; }, 'button_text' => '保存', 'before_callback' => function ($crud, $request) { $this->syncColorInventories($crud->entry, $request); return true; }, ]);
在setupUpdateOperation()中复用同步逻辑(封装为私有方法):
private function syncColorInventories($product, $request) { $colorInventories = $request->input('color_inventories', []); $syncData = []; foreach ($colorInventories as $inventory) { if (!empty($inventory['color_id']) && !empty($inventory['number'])) { $syncData[$inventory['color_id']] = ['number' => $inventory['number']]; } } $product->colors()->sync($syncData); $request->request->remove('color_inventories'); }
配置完成后,提交的颜色库存数据会正确同步到colorables_table,不会存入商品表的字段中。
内容的提问来源于stack exchange,提问作者Maya Hamdan
相关产品推荐
相关产品推荐

