首页 > 解决方案 > Laravel 7 - 数组到数据库(复选框)

问题描述

我正在为医疗慈善机构创建仪表板。

我在 Laravel 7 中有一个多步骤表单设置。它分三个步骤记录事件(因此使用 session())。在第 2 步,它要求用户选择给药的药物。药物来自数据库表(药物),并使用他们检查的内联复选框显示给用户。然后将其作为数组返回给控制器。

我的问题如下:

BLADE VIEW (addincident2.blade.php) [... 替换了一些删除的代码以便于阅读]

<form method="POST" action="{{ route('incident.doadd.2') }}">
    @csrf
    ...                         
    <div class="form-group row">
    <label for="incident_drugs" class="col-md-4 col-form-label text-md-right">{{ __('Drugs Used') }}</label>
        <div class="col-md-6">
            <div class="form-check">
            @foreach ($drugs as $drug)
            <label class="form-check-label">
                <input class="form-check-input @error('incident_drugs') is-invalid @enderror" name="drugs_used[]" type="checkbox" id="{{ $drug->drug_name }}" value="{{ $drug->drug_name }}">{{ $drug->drug_name }}
            </label></br >
            @endforeach
        </div>
            @error('incident_drugs')
            <span class="invalid-feedback" role="alert">
                <strong>{{ $message }}</strong>
            </span>
            @enderror
        </div>
    </div>                      
    ...
</form>

事件控制器

    // NEW INCIDENT ADD METHOD
public function AddIncidentPage1 (Request $request) 
{
    $request->session()->forget('incident');
    $request->session()->forget('drugused');
    $incident = $request->session()->get('incident');
    $drugused = $request->session()->get('drugused');
    $pagetitle = "Add an Incident"; 
    $incidenttypes = DB::table('incident_types')->pluck('incident_type');
            
    return view('incidents.addincident1', compact('pagetitle', 'incidenttypes', 'incident', 'drugused'));
}

public function DoAddIncident1 (Request $request)
{
    $validatedData = $request->validate([
    'incident_date' => 'required|date',
    'incident_number' => 'required|numeric|digits:8',
    'incident_location' => 'required|alpha_num|min:2|max:4',
    'incident_type' => 'required',
    'incident_desc' => 'required',
    'incident_duration' => 'required',
    'incident_work' => 'boolean',
    'incident_mileage' => 'numeric',
    'incident_case_review' => 'boolean',
    'incident_sd' => 'boolean',
    ]);
    
    $incident = new Incident();
    $incident->fill($validatedData);
    $request->session()->put('incident', $incident);
    
    if($validatedData['incident_sd'] == 0)
    {
        return redirect('/incidents/add/2');
    }
    elseif($validatedData['incident_case_review'] == 1)
    {
        return redirect('/incidents/add/3');
    }
    else
    {
        $incident = $request->session()->get('incident');
        $incident->fill($validatedData);
        $incident->incident_userid = Auth::user()->esr_number;
        $incident->save();
        return redirect()->intended('/incidents')->with('success','Incident created successfully!');
    }
}

public function AddIncidentPage2 (Request $request) 
{
    $incident = $request->session()->get('incident');
    $drugused = $request->session()->get('drugused');
    $drugs = Drug::all();
    
    $pagetitle = "Add an Incident"; 
            
    return view('incidents.addincident2', compact('pagetitle', 'incident', 'drugs', 'drugused'));
}

public function DoAddIncident2 (Request $request)
{
    $validatedData = $request->validate([
    'incident_fos' => 'boolean',
    ]);
    $incident = $request->session()->get('incident');
    $incident->fill($validatedData);
    $request->session()->put('incident', $incident);

    
    if($incident['incident_case_review'] == 1)
    {
        return redirect('/incidents/add/3');
    }
    else
    {
        $incident->incident_userid = Auth::user()->esr_number;
        $incident->save();
        return redirect()->intended('/incidents')->with('success','Incident created successfully!');
    }
}

public function AddIncidentPage3 (Request $request) 
{
    $incident = $request->session()->get('incident');
    $drugused = $request->session()->get('drugused');
    
    $pagetitle = "Add an Incident"; 
            
    return view('incidents.addincident3', compact('pagetitle', 'incident', 'drugused'));
}

public function DoAddIncident3 (Request $request)
{
    $validatedData = $request->validate([
    'incident_review_notes' => 'required_if:incident_case_review,1',
    ]);

        $incident = $request->session()->get('incident');
        $incident->fill($validatedData);
        $incident->incident_userid = Auth::user()->esr_number;
        $incident->save();
        $request->session()->forget('incident');


    return redirect()->intended('/incidents')->with('success','Incident created successfully!');
}

标签: phplaravel

解决方案


不要使用药物名称作为复选框的 ID(或 value="" 字段)。使用唯一的数据库 ID。

当你命名一个以 [] 结尾的 html 字段时,PHP 会将它变成一个数组。

    $user = $reqest->user();
    //is user related to drugs via drugs used?

    $drugsSubmitted = $request->input('drugs-used');
    $drugsSubmitted->each(function($item) use ($user) {
        $loadedDrug = \App\Models\Drug::find($item); //because it is a list of IDs from HTML POST
        $user->drugs()->associate($loadedDrug);
    });
    $user->drugs()->save();

但这并没有消除任何以前的关系。我们希望提交的内容是所用药物的最终清单。所以我们必须在调用之前清除该用户的现有关系$model->relation()->associate( $modelB )

您可以使用$model->relation()->sync( $arrayOfIds )同步方法在 1 次调用中保存相关 ID 的绝对列表。

通过 DrugsUsed 表可以实现用户和所有可能的药物之间的关系,如下所示:


class User {
    public function drugs() {
        return $this->belongsToMany('App\Models\Drug');
        //optionally you can specify the table which holds the many-to-many ids
        // return $this->belongsToMany('App\Models\Drug', 'user_drug_rel');
    }
}

(您需要通过迁移自己创建多对多表)

php artisan make:migration create_user_drug_relation_table
public function up()
{
    Schema::create('user_drug_rel', function($table) {
        $table->increments('id');
        $table->integer('user_id');
        $table->integer('drug_id');
        $table->timestamps();
    });
}

描述了保存多对多关系的“标​​准”方法(https://laravel.com/docs/6.x/eloquent-relationships)我不会将数据保存限制为仅一种方法。

当有人处理临床数据时,我通常会跳到 EAV 建模,因为数据可能会在研究的整个生命周期内发生变化。哪些药物可用,可能选择或可能不选择可能会改变。他们可能会在 6 个月后再次问同样的问题。

我会根据它们的 ID(如第一个each循环)从数据库中加载所有药物,并将药物名称、ID、日期和许多其他内容保存到 json blob 中并将其存储在表中喜欢user_form_submissions。这样,如果有人回击并更改复选框并再次提交,您将获得一个不断增加(仅附加)提交时间的日志。

现在我已经阅读了您的事件控制器。我肯定会在该表中添加一个 json blob 列,然后循环提交的药物 ID 并创建一个数组数组。

此外,您可以创建一个事件并将 ID 作为隐藏输入类型放入表单中,而不是尝试在会话中传递对象/ID。


//Incident controller

public function doSavePage1(Request $req) {
    //validate
    $i = Incident::create([
         'attribute' => $request->input('attribute'),
         // etc...
    ]);

    return view('step.2.template', [
        'incident_id' => $i->id,
    ]);
}


public function doSavePage2(Request $req) {
    $i = Incident::find($request->input('incident_id'));
    if($i ==null) {
        return response()->back();
    }
}

推荐阅读