Laravel模型验证:如何仅允许一个相关模型

时间:2019-10-09 20:53:21

标签: php laravel validation laravel-5

我有一个带有录音的模型Training

enter image description here

在我的模型Observation中,我必须注意训练的反馈。

理想的行为是每次训练仅允许一个观察。例如,如果我接受了3次训练,则可以输入3个观察值。我的问题是我的代码允许我为每次培训添加多个观察值。我想通过一条错误消息更好地解决这个问题。

enter image description here

现在这是我的代码的想法

public function store(Request $request)
{
  $request->validate([
    'instruction' => 'required',
    'description' => 'required',
    'fk_student' => 'required'
  ]);

  $instruction = $request->get('instruction'); 
  $description = $request->get('description');
  $fk_student = $request->get('fk_student');

  $trainings = Training::where('fk_student', $request->get('fk_student'))->first();

  if(!isset($trainings)){ 
    return redirect()->route('observations.index')
                     ->with('error', 'No training, no observation! ');
  } else {
    Observation::create($request->all());
    return redirect()->route('observations.index')
                     ->with('success', 'Add');
  }
}

2 个答案:

答案 0 :(得分:1)

有几种方法可以解决此问题。我将在此处提供三种解决方案,但请记住,您可以选择实施三种方案之一,三种方案的某种组合或完全不同的方案。


方法1:前端

我个人认为这是最好的解决方案。这是最简单的实施,并且可以产生预期的结果。您所要做的就是如果Training已经记录了Observation,则禁用“添加”按钮:

your-view.blade.php:

<h1>Listing Observations</h1>

<!-- Observations Table -->

<button{{ $training->observations()->exists() ? ' disabled' : '' }}>Add</button>

对于该应用程序的所有用户而言,这将足够99.999%。当然,尽管禁用了按钮,但是精明的用户仍然可以提交请求。在我看来(愤世嫉俗),我不会为试图绕开系统的用户而烦恼“优雅地失败”。

但这取决于您。您可以实施此方法并将其称为好方法。如果您决定希望系统更强大,则可以实现方法2或方法3。

  

注意:我认为,如果您选择实施方法2或3, 您还应该实施方法1 。它的实现非常简单,并且比允许用户完成Observation表单,然后告诉他们只允许创建一个Observation的情况,它提供了更好的UX。


方法2:后端-雄辩

口才允许您query the existence使用相关模型。这意味着您可以在创建Training之前先检查一下Observation是否已有相应的public function store(Request $request) { $request->validate([ 'instruction' => 'required', 'description' => 'required', 'fk_student' => 'required' ]); $instruction = $request->get('instruction'); $description = $request->get('description'); $fk_student = $request->get('fk_student'); $trainings = Training::where('fk_student', $request->get('fk_student'))->first(); if(!isset($trainings)){ return redirect()->route('observations.index') ->with('error', 'No training, no observation! '); } if ($trainings->observations()->exists()) { /****************************************************************************** * I'm returning a plain text response. Depending on your front end code, it * might make more sense to return a JSON response. Whatever response type you * choose, make sure that you respond with an HTTP error code. I think * 400 – Bad Request makes the most sense). ****************************************************************************** */ return response('An Observation already exists for this Training', 400) ->header('Content-Type', 'text/plain'); } // If we make it to this point, it is safe to go ahead and create the Observation Observation::create($request->all()); return redirect()->route('observations.index') ->with('success', 'Add'); }

Observations

方法3:后端–数据库

最后,您可以让数据库为您处理。该方法的思想是创建一个数据库约束,以将每个Training的{​​{1}}的数量限制为一个。有了该约束,您就可以在一切都完美的前提下处理表单提交。

但是,由于一切都是 不是 ,因此总是非常完美的,因此必须用try/catch块包围代码,并处理数据库的异常情况将抛出。

/****************************************************************
 * You can add this to a new or an existing database migration.
 ****************************************************************
 */
public function up()
{
  Schema::table('observations', function($table) {
    $table->unsignedInteger('training_id')
          ->unique()
          ->nullable();
  });
}

YourController.php

public function store(Request $request)
{
  $request->validate([
    'instruction' => 'required',
    'description' => 'required',
    'fk_student' => 'required'
  ]);

  $instruction = $request->get('instruction'); 
  $description = $request->get('description');
  $fk_student = $request->get('fk_student');

  $trainings = Training::where('fk_student', $request->get('fk_student'))->first();

  if(!isset($trainings)){ 
    return redirect()->route('observations.index')
                     ->with('error', 'No training, no observation! ');
  }

  try {
    Observation::create($request->all());
    return redirect()->route('observations.index')
                     ->with('success', 'Add');
  } catch (\Exception $e) {
    /******************************************************************************
     * You shouldn't *really* return `$e->getMessage()` to the user. Just return
     * an error message that makes sense for the action the user attempted.
     ******************************************************************************
     */
    return response($e->getMessage(), 400)->header('Content-Type', 'text/plain');
  }
}

答案 1 :(得分:-1)

使表观察的外键唯一:

$table->bigInteger('training_id')->unsigned()->unique();

并验证 'unique:observations,training_id'