Laravel

【Update Screen Checkbox Edition】How to Update One-to-Many Related Data in Laravel

In the past, I introduced
【Update Screen Textbox Edition】How to Update One-to-Many Relational DB Data in Laravel (With Add/Delete of “Many” Records)
but that covered only textboxes (type=”text”).
This time, I will introduce how to update the main table and its child (many) table using checkboxes on the update screen.
The number of child records can increase or decrease (add/delete on the update screen).
(Laravel version 6 series)

Table Structure of Two Tables with Parent-Child Relationship (One-to-Many)

Two tables with a parent-child relationship (one-to-many) are prepared.
This structure registers multiple employee IDs (employees table) that belong to a department (departments table).

Department Table: departments Table (Parent)

Name Description
id Primary Key
department_name Department Name

Employee Table: employees Table (Child)

Name Description
id Primary Key
employee_id Employee ID
department_id Department ID = id of departments table
*The name must be “department_id,” created by taking the table name “department” (singular, without “s”) and adding an underscore and the primary key name “id”.
This allows retrieving data where the id matches in the departments table.

Prepare Models for Parent and Child Table Data

*Prepare Department model and Employee model.

Model Description for departments Table (Parent)

*Prepare Department.php file.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Department extends Model
{

}

Model Description for employees Table (Child)

*Prepare Employee.php file.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Employee extends Model
{

}

Update Form View for Department and Employee IDs (Checkbox)

*Prepare departmentsedit.blade.php.
This update form allows checking up to 5 employee IDs (checkbox) per department.

        @if (session('message'))
            <div class="message">
                {{ session('message') }}
            </div>
        @endif

@include('common.errors')

<form enctype="multipart/form-data" action="{{ url('departments/update') }}" method="POST">
@csrf

<div>
    <label for="id">Department ID</label>
        <div>{{$department->id}}</div>
        <input type="hidden" name="id" value="{{$department->id}}">
</div>

<div>
    <label for="department_name">Department Name※</label>
    <input type="text" id="department_name" name="department_name" value="{{ old('department_name') }}">
</div>

<ul>
@for($idx=0;$idx<5;$idx++)
    <li>
    <?php
    // If the registered employee ID matches the checkbox value, mark as checked
    $employee_id = "";
    $value_id = $idx+1;
    for($i=0;$iemployee_id)){
            if($employees[$i]->employee_id == $value_id){
                $employee_id = $employees[$i]->employee_id;
                break;
            }
        }
    }
    ?>
    <label>Employee ID{{ $value_id }}</label>
    <input type="checkbox" value="{{ $value_id }}" name="employee_id[{{ $idx }}]" @if( old("employee_id.$idx", $employee_id) == $value_id) ) checked @endif>
    </li>
@endfor
</ul>

<button type="submit" class="btn-entry">Update</button>

</form>

Route Description

*Change the page URL as needed.

//Update screen
Route::post('/departmentsedit/{departments}','DepartmentsController@edit');
//Update process
Route::post('/departments/update','DepartmentsController@update');

Controller Description to Update One-to-Many Related Data

*When updating the parent table (departments), using its id (primary key), foreach + save() is used to update/create records in the child employees table.
Finally, if the number of employee IDs checked on the update screen is less than the number of records registered in employees table, the extra records are deleted. (DepartmentsController.php)

Load Department and Employee Models

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

use App\Department;   // Use Department model
use App\Employee;     // Use Employee model
use Validator;        // Use validation
use DB;

Controller Description for Update Screen and Update Process (Checkbox)

*This includes the update screen display “edit($id)” and the update process “update(Request $request)”.

  • In the update process, after input, “//Validation Check” is performed, then “Update Department Table (Parent)” is processed, and afterward, “//Retrieve Checked Employee IDs as an Array”.
  • “Retrieve multiple records from employees table (child) where department_id matches the parent id”.
  • Inside foreach:
    “//Loop through checked employee IDs from the update screen.”
    “//If fewer records exist in employees than checked items, update.”
    “//If more checked items exist than employees records, create new records.”
  • Finally: “//If the number of employees records is larger than checked items, delete the extra employee records.”
class DepartmentsController extends Controller{

    //Update screen
    public function edit($id)
    {
        $department = Department::find($id);
        $employees = DB::select("SELECT * FROM employees WHERE department_id = ".$id."");
        return view('departmentsedit', [
            'department' => $department,
            'employees' => $employees,
        ]);
    }


    //Update process
    public function update(Request $request) {
        //Validation check
        $validator = Validator::make($request->all(), [
            'department_name' => 'required',
            'department_name' => 'max:255',
        ]);

        //Validation error 
        if ($validator->fails()) {
                return redirect('/departmentsedit')
                    ->withInput()
                    ->withErrors($validator);
        }

        //Update parent department table
        $departments = Department::find($request->id);
        $departments->department_name = $request->department_name;
        $departments->save();

        //Get checked employee IDs as array
        $employee_ids = $request->get('employee_id');

        //If no data, initialize array
        if (!is_array($employee_ids)) {
            $employee_ids = array();
        }

        //Parent department id (primary key)
        $department_id = $request->id;

        //Retrieve child employee records matching department_id
        $employees = Employee::where('department_id', $department_id)->get();

        $i = 0;
        //Loop through checked employee IDs
        foreach ($employee_ids as $j => $employee_id) {
            //If existing employee records < checked items → update
            if($i < count($employees)){
                $employees[$i]->employee_id = $employee_ids[$j];
                $employees[$i]->save();
            //If existing employee records < checked items → create
            }else{
                $employee = New Employee;
                $employee->department_id = $department_id;
                $employee->employee_id = $employee_ids[$j];
                $employee->save();
            }

            $i++; 
        }//END foreach

        //If employees table has more records than checked items → delete the extra ones
        if($i < count($employees)){
            for($i=$i; $iid)->delete();
            }
        }

        return redirect('/departmentsedit')->with('message', 'Data has been updated');
    }

}

*If you reuse this code, please do so at your own responsibility.