我有两个具有oneToMany关系的Model类,比如这个
应用\车class Car extends Model
{
public $timestamps = true;
protected $fillable = [
'name',
'price'
];
public function parts ()
{
return $this->hasMany('App\Part');
}
}
应用程序\部分
class Part extends Model
{
public $timestamps = false;
protected $fillable = [
'name',
'price'
];
public function car ()
{
return $this->belongsTo('App\Car');
}
}
客户端发出一个POST请求,其中JSON表示带有嵌套数组部件的Car
{
"name": "Fiat Punto",
"price": 15000,
"parts": [
{
"name": "wheel",
"price": 300
},
{
"name": "engine",
"price": 5000
}
]
}
有没有办法保存Car模型并在一次点击中创建关系?
我试图在我的控制器中执行此操作,但它不起作用:
...
public function store (Request $request) {
$input = $request->all();
Car::create($input);
}
...
PS:我已经知道如何使用foreach
或array_reduce
完成任务,只是想知道laravel是否可以为我做这件事
以下是我现在如何实施控制器:
...
public function store (Request $request) {
$input = $request->all();
$car = Car::create($input);
$parts = array_reduce(
$input['parts'],
function ($carry, $item) {
array_push($carry, new Part($item));
return $carry;
},
[]
);
$car->parts()->saveMany($parts);
}
...
欢迎任何改进
答案 0 :(得分:3)
我认为有一种方法可以解决您需要创建请求对象中定义的每个App \ Part模型实例的问题。因此,在某些时候,您必须迭代请求对象中的那些项,这意味着您(至少)有两个选项。这些都是described here。
在旁注中我认为在这种情况下最好使用foreach循环作为第一个选项:
foreach ($request->input('parts') as $item) {
$car->parts()->save(new Part($item));
}
如果您要先将第二个选项存储在数组中,那么我认为array_map是更合适的方法(因为没有实际的“减少”):
$parts = array_map(function($part) {
return new App\Part($part);
}, $request->input('parts'));
$car->parts()-saveMany($parts);
编辑:根据@TomasKim的建议,只有2个查询 - 一个用于Car模型,另一个用于Part模型:
$parts = array_map(function($part) {
return [...$part, 'car_id' => $car->id];
}, $input['parts'])
DB::table('parts')->insert($parts);
答案 1 :(得分:3)
虽然没有一种技术上可以完全自动完成此操作的方法,但只需调整fillable
属性并添加方法,就可以使模型的雄辩api以这种方式运行:
class Car extends Model
{
public $timestamps = true;
protected $fillable = [
'name',
'price',
'parts',
];
public function parts ()
{
return $this->hasMany('App\Part');
}
public function setPartsAttribute($parts)
{
foreach ($parts as $part) {
Part::updateOrCreate(
['id' => array_get($parts, 'id')],
array_merge($part, ['car_id' => $this->id])
);
}
// ... delete parts not in the list if you want
}
}
注意我们刚刚将parts
添加到fillable属性,然后使用Eloquent的属性设置hook set[Field]Attribute()
来执行赋值。这样就可以让Car
api看起来正确:
Car::find(1)->update($carWithParts);
注意:创建Car
模型时,这不起作用,因为没有id
。如果您想自动执行此操作,则可以对这些更新进行排队,然后使用模型的事件挂钩来执行此操作。