【问题标题】:Laravel model validation: How to allow only ONE related modelLaravel 模型验证:如何只允许一个相关模型
【发布时间】:2020-02-07 06:17:25
【问题描述】:

我有一个模特Training 有录音

在我的模型Observation中,我不得不记下训练的反馈。

期望的行为是每次训练只允许一次观察。例如,如果我有 3 次训练,我可以输入 3 次观察。我的问题是我的代码允许我为每次训练添加几个观察结果。我想通过错误消息更好地处理它。

这是我现在的代码的想法

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');
  }
}

【问题讨论】:

  • 你能澄清期望的行为吗?我认为你想要的是:如果一个训练已经有一个观察,你不能添加另一个观察。或者换句话说,一次训练最多可以有 1 个观察值。我有这个权利吗?
  • 嘿@user11124425,我想帮助你,但你没有提供足够的信息。回答我上面的问题,我会看看我能做些什么。
  • 嗨@Vince,对不起,就是这样......谢谢你的帮助。
  • 好的@user11124425,我已经编辑了您的问题以澄清所需的行为。如果我有什么问题,请随时回滚您不同意的任何编辑。这应该使您更容易获得这方面的帮助。如果仍未得到答复,我将在今天晚些时候回过头来。
  • 好的,谢谢@Vince,我卡住了... :-(

标签: php laravel validation laravel-5


【解决方案1】:

使表观察的外键唯一:

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

并验证 'unique:observations,training_id'

【讨论】:

    【解决方案2】:

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


    方法一:前端

    就个人而言,我认为这是最好的解决方案。它是最容易实现的,并且会产生预期的结果。如果Training 已经记录了Observation,您所要做的就是禁用“添加”按钮:

    你的视图.blade.php:

    <h1>Listing Observations</h1>
    
    <!-- Observations Table -->
    
    <button{{ $training->observations()->exists() ? ' disabled' : '' }}>Add</button>
    

    这对于该应用程序的 99.999% 的所有用户来说已经足够了。当然,即使按钮被禁用,精明的用户仍然可以提交请求。在我(愤世嫉俗的)看来,我不会为试图绕过系统的用户“优雅地失败”。

    但这取决于你。你可以实现这个方法并称之为好。如果您决定希望系统更加健壮,您可以实现方法 2 或方法 3。

    注意:在我看来,如果您选择实施方法 2 或 3,您仍然应该实施方法 1。它实现起来超级简单,而且它提供了比允许用户填写Observation 表单,然后告诉他们只允许创建一个Observation 更好的用户体验。


    方法二:后端——Eloquent

    Eloquent 允许您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');
    }
    

    方法三:后端——数据库

    最后,您可以让数据库为您处理这个问题。此方法背后的想法是您创建一个数据库约束,将每个TrainingObservations 数量限制为一个。有了这个约束,您就可以假设一切都很完美来处理表单提交。

    但是,由于一切都总是完美无缺,因此您必须用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');
      }
    }
    

    【讨论】:

    • Waaaaawwwww 非常感谢 Vince,感谢您的代码和时间。我的问题解决了。万分感谢。 :-)
    • 没问题——很高兴能帮上忙!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-07
    • 1970-01-01
    相关资源
    最近更新 更多