Laravel 验证控制器存储中的变量

Posted

技术标签:

【中文标题】Laravel 验证控制器存储中的变量【英文标题】:Laravel validate a variable in controller store 【发布时间】:2018-08-29 09:22:03 【问题描述】:

我的问题找不到答案,希望有人能帮助我

我想验证我是否添加了一个新的约会,而所选员工在约会当天尚未被选中。所以我不能在一天内重复预订某人。 我正在使用 laravel 5.6 和 mysql 与表约会使用以下行: id、day、employee_id 和 resource_id

我的控制器是一个资源控制器(具有索引、创建、存储等功能)。

因此,如果 $appointmentExists 为 1,我需要抛出错误并停留在创建表单的同一页面上。

public function store(Request $request)

    $appointmentExist = \DB::table('appointments')
        ->where([
            ['day','=',$request->day],
            ['employee_id','=',$request->employee_id],
        ])
        ->exists();
    $request->validate([
        'day' => 'required|min:1|max:10',
        'employee_id' => 'required',
        'resource_id' => 'required',
        $appointmentExist => 'in:0',
    ]);
    $appointment = Appointment::create(['day' => $request->day, 'employee_id' => $request->employee_id, 'resource_id' => $request->resource_id]);
    return redirect('/appointments/' . $appointment->id);

希望有人能帮忙

【问题讨论】:

如果你问数据库是否有记录,那并不意味着杰克。双重预订仍然是可能的。你要做的就是在[day, employee_id] 上设置一个唯一的约束,那么数据库肯定不会允许超过 1 条记录。下一步是插入数据。如果记录存在,Laravel 将抛出异常。代码23000 表示duplicate record。您可以使用它来告诉您的用户已预约。 【参考方案1】:

所以我自己找到了答案,也许其他人可以使用它:

if(\DB::table('appointments')
    ->where([
        ['day','=',$request->day],
        ['employee_id','=',$request->employee_id],
    ])
    ->exists())
        return redirect()->back()->withErrors(['This employee is already busy for that day, select another employee or another day.']);
    ;

所以现在我回复错误“该员工那天已经很忙了,...”。 我还没有找到如何从 $request->validate() 返回错误,但在这种情况下我不需要它。如果您知道,请随时告诉我。

【讨论】:

【参考方案2】:

你的问题是这一行:

$appointmentExist => 'in:0',

这是检查in_array($request->input($appointmentExist), [0]),但$request->input($appointmentExist) 将检查$request->input(0)$request->input(1),这两种技术在技术上都不存在。

我会改为使用请求添加:

$exists = \DB::table(...)->exists(); // Same query, just assigned to a variable
$request->request->add(["exists", $exists]);

$request->validate([
  ...,
  "exists" => "in:0"
]);

通过将密钥 "exists" 添加到请求负载中,您可以像验证请求中发送的实际数据一样验证它,并立即返回所有错误。

根据@N.B. 的评论,以上内容只会防止这种情况下的重复预订;如果验证失败,则永远不会调用Appointment::create(),也不会插入数据。

考虑到这一点,如果验证意外通过,最好有一个回退,在这种情况下,如果您真的想防止重复预订,则对 employee_idday 的组合使用 unique 约束,并像这样处理:

try 
  Appointment::create(...);
catch (\Illuminate\Database\QueryException $qex)
  \Log::error("Unable to Create Appointment: ".$qex->getMessage());

  // Handle individual codes
  if($qex->getCode() == "23000")
    return redirect()->back()->withErrors(...);
  

【讨论】:

这不会阻止重复预订。 @N.B.我在上面看到你的评论。当我做验证时,我做$validator = \Validator::make(...); ... if($validator->passes()) ... ;;我从未真正使用过$request->validate()。这里是否缺少步骤? 验证本身很好,保存部分并询问数据库是否存在记录。 OP 应该验证基本信息,例如是否存在 employee_id 等等。下一部分,验证记录是否存在不会进入验证逻辑。您只需插入(并预先放置唯一约束)。如果抛出异常,记录就在那里,此时您可以使用消息appointment exists 捕获并重新抛出ValidationException。这样您就可以 100% 确定不会出现“同时有两个用户”的问题。 @N.B.我同意你所说的一切;肯定有更好的方法来处理重复预防。话虽如此,这个答案的意思是提问者关于如何一次返回所有验证消息的原始答案的地址,更重要的是关于为什么$appointmentExist => 'in:0' 是“无效验证”的逻辑错误。不过感谢您的反馈。 请记住,OP 还写道:So I can't double-book someone on a day.。如果您包括防止重复预订的部分,我将非常乐意支持您的回答。我评论的原因是很多人会在谷歌上搜索并偶然发现这个答案。【参考方案3】:
$request->validate([
        'day' => 'required|min:1|max:10',
        'employee_id' => 'required',
        'resource_id' => 'required',
        $appointmentExist => 'in:0',
    ]);

此无效代码。验证器将在请求数据中搜索 1 或 0 ($appointmentExist)。这些键永远不会包含在此请求中。

尝试使用规则类。示例:

$day = $request->day;

$request->validate([
    'day' => 'required|min:1|max:10',
    'employee_id' => [
        'required',
            Rule::unique('appointments')->where(function ($query) use ($day) 
               return $query->where('day', $day);
            )
        ],
    'resource_id' => 'required'
]);

【讨论】:

这也不会阻止重复预订。

以上是关于Laravel 验证控制器存储中的变量的主要内容,如果未能解决你的问题,请参考以下文章

将获取的值分配给 laravel 控制器中的变量

Laravel 中的 required_if 验证

将数据从控制器传递到 Laravel 中的视图

Laravel 5.2 验证错误

在 laravel 刀片路由中使用 JavaScript 变量

Laravel 表单验证,为啥我的视图中没有可用的 $errors 变量?