我有两个能言善辩的模型:
class User extends Model
{
public function items()
{
return $this->hasMany(Item::class, "userId");
}
}class Item extends Model
{
public function user()
{
return $this->belongsTo(User::class, "userId");
}
}Item的专栏包括id、userId和name。
当我想更新用户(PUT /users/<id>)时,我也希望在同一个请求中更新项目,这意味着:
之后,DB和关系都应该有最新的项目。
请求数据示例:
{
"userAttribute1": "Something",
"userAttribute2": "Something else",
"items": [
{
"name": "Name1"
},
{
"name": "Name2"
}
]
}我试着用Laravel寻找一种简单的方法来实现这一点,例如,对于多到多的关系,您只需调用attach/detach和sync,就可以用ids自动更新它们。
我已经为我的一对多的关系而使这令人憎恶:
// 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),
];
}这个用户+条目模型只是一个例子--我有多个类似的关系(不仅仅是name列),复制粘贴这段代码,稍微修改一下它似乎有点傻。
Laravel以所有这些花哨的快捷方式和易于使用/魔术的方法而闻名,所以我在这里的问题是:是否有一种更简单、更短的方法来进行此更新?
发布于 2021-05-14 01:52:59
您可以使用Laravel收藏品。
首先,更新用户:
$user->update($request->validated());然后,您可以同步用户项:
$new = ['item 1', 'item 2']; // Your request items
// Get the current items your user have:
$items = $user->items->pluck('name')->toArray();
// Now, you need to delete the items your user have but are not present in the request items array:
$deleteItems = $user->items->pluck('name', 'id')
->reject(function($value, $id) use ($new) {
return in_array($value, $new);
})
->keys();
Item::whereIn('id', $deleteItems)->delete();
// Last but not least, you need to create the new items and attach it to the user:
collect($new)->each(function($insertData) use ($user) {
$user->items()->firstOrcreate([
'name' => $insertData
]);
});对于具有多个字段的模型,需要将两个数组传递给firstOrCreate方法。第一个数组将用于查找模型,如果未找到,则将通过两个数组的合并创建该数组:
$user->items()->firstOrcreate([
'name' => $insertData
], [
'description' => $description,
'quantity' => $quantity
]);由于您使用的是firstOrCreate,所以它只会在没有名称找到的情况下创建项目,并且不会有重复的项。
https://stackoverflow.com/questions/67516738
复制相似问题