使用 Laravel 中多个复选框的 attach() 更新多对多关系数据

Posted

技术标签:

【中文标题】使用 Laravel 中多个复选框的 attach() 更新多对多关系数据【英文标题】:Updating many-to-many relational data with attach() from multiple checkboxes in Laravel 【发布时间】:2021-12-26 12:40:49 【问题描述】:

我正在 Laravel 中创建一个在线书店,创建新书后,管理员可以通过选中特定的仓库复选框来定义哪些仓库可以存放这本书。 为了深入了解它的工作原理,这是我的创建函数:

public function create()

    $authors = Author::all();
    $selectedAuthor = Book::first()->author_id;

    $publishers = Publisher::all();
    $selectedPublisher = Book::first()->publisher_id;

    $warehouses = Warehouse::all();
    $selectedWarehouse = Book::first()->warehouse_id;

    return view('books.create', compact(['authors', 'publishers', 'warehouses'],
                    ['selectedAuthor', 'selectedPublisher', 'selectedWarehouse']
    ));

还有我的存储方法:

public function store(Request $request)

    $request->validate([
        'ISBN' => 'required',
        'author_id' => 'required',
        'publisher_id' => 'required',
        'year' => 'required',
        'title' => 'required',
        'price' => 'required',
    ]);

    try 
        $book = Book::create($request->all());

        foreach ($request->checked as $value)
            $book->warehouses()->attach([$value]);
        

        return redirect()->route('books.index')
            ->with('success','Book created successfully.');

     catch (\Illuminate\Database\QueryException $e) 
        var_dump($e->errorInfo);
    

但是当管理员编辑一本书时,创建该书时选中的复选框应该是“选中”,并且管理员应该能够附加更多的仓库,并且能够“取消选择”一个仓库,所以如果一个已经检查过的值被取消检查和提交,它应该从多对多表中分离出来。

这是我目前拥有的: 我的编辑方法:

public function edit(Book $book)

    $authors = Author::all();
    $selectedAuthor = Book::first()->author_id;

    $publishers = Publisher::all();
    $selectedPublisher = Book::first()->publisher_id;

    $warehouses = Warehouse::all();
    $selectedWarehouse = Book::first()->warehouse_id;

    return view('books.edit', compact(['book', 'authors', 'publishers', 'warehouses'],
                    ['selectedAuthor', 'selectedPublisher', 'selectedWarehouse']));

还有我的更新方法:

public function update(Request $request, Book $book)

    $request->validate([
        'ISBN' => 'required',
        'publisher_id' => 'required',
        'author_id' => 'required',
        'year' => 'required',
        'title' => 'required',
        'price' => 'required',
    ]);

    try 
    $book->update($request->all());

    // TODO: Update warehouses

        return redirect()->route('books.index')
            ->with('success','Book updated successfully.');

     catch (\Illuminate\Database\QueryException $e) 
        var_dump($e->errorInfo);
    

还有我的 edit.blade 视图中的复选框:

@foreach($warehouses as $warehouse)
    <input type="checkbox" name="checked[]" value=" $warehouse->id ">
     $warehouse->address 
    <br/>
@endforeach

我的书模型:

public function warehouses()

    return $this->belongsToMany(Warehouse::class);

还有我的仓库模型:

public function books()

    return $this->belongsToMany(Book::class);

任何关于在编辑现有书籍时能够附加/分离的帮助,将不胜感激!

【问题讨论】:

你试过sync()函数吗? 【参考方案1】:

在创建和更新存储方法上试试这个

// Your method
foreach ($request->checked as $value)
    $book->warehouses()->attach([$value]);


// Try This
$book->warehouses()->sync($request->checked); // $request->checked must be an array

更新刀片

@foreach($warehouses as $warehouse)
    <input @if($book->warehouses()->where('warehouse_id', $warehouse->id)->exists()) checked @endif type="checkbox" name="checked[]" value=" $warehouse->id ">
     $warehouse->address 
    <br/>
@endforeach

【讨论】:

这很完美!,你知道如何在edit.blade视图中的复选框列表中显示已经选中的仓库吗?就像现在,在编辑一本书时,所有复选框都未选中。 嗯.. 这实际上更新了它们,所以为了解决这个问题,我需要在多对多表中当前处于活动状态的复选框,以便在编辑书籍时预先选择. 我更新了我的答案【参考方案2】:

我会根据你的问题给这个例子留下一个逻辑。在这种情况下是角色:

public function edit(Role $role)
        //get roles ids
        $permission_role = [];
        foreach($role->permissions as $permission)
            $permission_role[] = $permission->id;
        
        //get permissions
        $permissions = Permission::all();

        return view("role.edit", compact('role', 'permission_role', 'permissions'));
    

在刀片中:

<div class="row">
    <div class="col-md-8">
        <div class="form-group">
          <label>Select the permissions for the current role</label>
        @foreach ($permissions as $permission)
        <div class="valid-feedback d-block" style="font-size: 15px !important;">
            <input  type="checkbox" value=" $permission->id " name="permissions[]"
                @if(is_array(old('permissions')) && in_array("$permission->id", old('permissions')))
                        checked
                @elseif(is_array($permission_role) && in_array("$permission->id", $permission_role))
                checked
                @endif>
            <strong>  $permission->description  </strong>
            </div>   
            @endforeach
        </div>

            <div class="invalid-feedback d-block">
            @foreach ($errors->get('permissions') as $error)
                   
                     $error 
                @endforeach
            </div>
    </div>
</div>

通过这种方式,您还可以在未选择任何内容时保留旧的复选框。您应该根据需要对其进行验证。

【讨论】:

谢谢,这很有意义,很高兴看到关于这个主题的一些验证。

以上是关于使用 Laravel 中多个复选框的 attach() 更新多对多关系数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在 LARAVEL_7 中通过迁移发送多个复选框

Laravel - 在数据库中存储多个复选框表单值

如何在 laravel 身份验证期间附加到用户创建多个复选框

Laravel 5.0 文件上传验证

在 laravel 5.3 中调用未定义的方法 Illuminate\Database\Query\Builder::attach()

Laravel:获取复选框的值