Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php Laravel更新模型';s一对多关系';s项目_Php_Laravel_Eloquent_One To Many - Fatal编程技术网

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),
        ];
    }