Php Laravel更新模型';s一对多关系';s项目
我有两个雄辩的模型:Php Laravel更新模型';s一对多关系';s项目,php,laravel,eloquent,one-to-many,Php,Laravel,Eloquent,One To Many,我有两个雄辩的模型: class User extends Model { public function items() { return $this->hasMany(Item::class, "userId"); } } Item的列包括id、userId和name 当我想更新用户(PUT/users/)时,我还想更新同一请求中的项目,这意味着: 跳过现有项目 添加新项目 删除额外的项目 之后,数据库和关系都应该有最新的项
class User extends Model
{
public function items()
{
return $this->hasMany(Item::class, "userId");
}
}
Item
的列包括id
、userId
和name
当我想更新用户(PUT/users/
)时,我还想更新同一请求中的项目,这意味着:
{
"userAttribute1": "Something",
"userAttribute2": "Something else",
"items": [
{
"name": "Name1"
},
{
"name": "Name2"
}
]
}
我试图用Laravel寻找一种简单的方法来实现这一点,例如,对于多对多关系,您只需调用attach
/detach
和sync
即可使用ID自动更新它们
我为我一对多的亲戚做了这件可憎的事:
// Controller method for PUT /users/<id>
public function update(User $user, Request $request)
{
// Update user attributes normal way
$user->fill($request->validated());
$user->save();
// Array, e.g. [ { "name": "Name1" }, { "name": "Name2" } ]
$newItems = $request->validated()["items"];
// Collection of items
$currentItems = $user->items;
// Array to keep track of which items to delete later
$removeItemIds = [];
foreach ($currentItems as $i => $currentItem)
{
// currentItem is Item model
$exists = false;
foreach ($newItems as $j => $newItem)
{
// newItem is array, e.g. { "name": "Name1" }
if ($currentItem->name === $newItem["name"])
{
$exists = true;
break;
}
}
if ($exists)
{
// New item already exists, remove from newItems array
unset($newItems[$j]);
}
else
{
// Current item does't exist anymore, remove from currentItems collection and mark as deletable
$removeItemIds[] = $currentItem->id;
unset($currentItems[$i]);
}
}
// Add remaining new items
foreach ($newItems as $newItem)
{
$item = Item::make($newItem);
$item->userId = $user->id;
$item->save();
$currentItems->push($item);
}
// Delete extra items
$user->items()->whereIn("id", $removeItemIds)->delete();
// Update relation so the returned data is up-to-date as well
$user->setRelation("items", $currentItems);
return [
"user" => new UserResource($user),
];
}
//PUT/用户的控制器方法/
公共功能更新(用户$User,请求$Request)
{
//以正常方式更新用户属性
$user->fill($request->validated());
$user->save();
//数组,例如。[{“name”:“Name1”},{“name”:“Name2”}]
$newItems=$request->validated()[“items”];
//物品的收集
$currentItems=$user->items;
//数组以跟踪以后要删除的项目
$removitemids=[];
foreach($currentItems作为$i=>$currentItem)
{
//currentItem是项目模型
$exists=false;
foreach($newItems为$j=>$newItem)
{
//newItem是数组,例如{“name”:“Name1”}
如果($currentItem->name===$newItem[“name”])
{
$exists=true;
打破
}
}
如果($存在)
{
//新项目已存在,请从newItems数组中删除
未结算($newItems[$j]);
}
其他的
{
//当前项不再存在,请从currentItems集合中删除并标记为可删除
$RemoveItemId[]=$currentItem->id;
未结算($currentItems[$i]);
}
}
//添加剩余的新项目
foreach($newItems作为$newItem)
{
$item=item::make($newItem);
$item->userId=$user->id;
$item->save();
$currentItems->push($item);
}
//删除额外项目
$user->items()->其中(“id”,$removitemids)->delete();
//更新关系,以便返回的数据也是最新的
$user->setRelation(“项目”、$currentItems);
返回[
“用户”=>新用户资源($user),
];
}
这个user+items模型只是一个例子——我有多个类似的关系(其中不仅仅是name
column)和复制—将此代码粘贴到任何地方并稍微修改它似乎有点愚蠢
Laravel以所有这些奇特的快捷方式和易于使用的/神奇的方法而闻名,所以我的问题是:有没有一种更简单、更短的方法来进行此更新?您可以使用
首先,更新用户:
$user->update($request->validated());
然后,您可以同步用户项目:
$new=['item 1','item 2'];//您的请求项目
//获取用户当前拥有的项目:
$items=$user->items->pull('name')->toArray();
//现在,您需要删除用户拥有但不在请求项数组中的项:
$deleteItems=$user->items->pull('name','id'))
->拒绝(函数($value,$id)使用($new){
以数组形式返回($value,$new);
})
->键();
Item::其中('id',$deleteItems)->delete();
//最后但并非最不重要的一点是,您需要创建新项目并将其附加到用户:
收集($new)->每个(函数($insertData)使用($user){
$user->items()->first或create([
“名称”=>$insertData
]);
});
对于具有多个字段的模型,需要将两个数组传递给first或create
方法。第一个数组将用于查找模型,如果找不到,将通过合并两个数组来创建:
$user->items()->first或create([
“名称”=>$insertData
], [
'description'=>$description,
“数量”=>$quantity
]);
由于您使用的是
first或create
,因此只有在未按项目名称找到项目时,它才会创建该项目,并且您不会有重复的项目。嘿,很抱歉回答得太晚!当只有一个字段(如我的示例中的“name”)时,这很好,但当项目有多个字段(如“id”、“name”、“value”)时,我无法让它工作。它还可以改变现有项的确定方式(例如,在示例中,只有“name”必须存在,也可以是“id”或两者兼有)。@bloodleh我已经更新了我的答案。谢谢,我成功了:)
// Controller method for PUT /users/<id>
public function update(User $user, Request $request)
{
// Update user attributes normal way
$user->fill($request->validated());
$user->save();
// Array, e.g. [ { "name": "Name1" }, { "name": "Name2" } ]
$newItems = $request->validated()["items"];
// Collection of items
$currentItems = $user->items;
// Array to keep track of which items to delete later
$removeItemIds = [];
foreach ($currentItems as $i => $currentItem)
{
// currentItem is Item model
$exists = false;
foreach ($newItems as $j => $newItem)
{
// newItem is array, e.g. { "name": "Name1" }
if ($currentItem->name === $newItem["name"])
{
$exists = true;
break;
}
}
if ($exists)
{
// New item already exists, remove from newItems array
unset($newItems[$j]);
}
else
{
// Current item does't exist anymore, remove from currentItems collection and mark as deletable
$removeItemIds[] = $currentItem->id;
unset($currentItems[$i]);
}
}
// Add remaining new items
foreach ($newItems as $newItem)
{
$item = Item::make($newItem);
$item->userId = $user->id;
$item->save();
$currentItems->push($item);
}
// Delete extra items
$user->items()->whereIn("id", $removeItemIds)->delete();
// Update relation so the returned data is up-to-date as well
$user->setRelation("items", $currentItems);
return [
"user" => new UserResource($user),
];
}