如何根据另一列强制执行 Laravel 数据库中记录的唯一性?



我有一个Laravel 8.x应用程序,它有一个包含列的数据库表:blockID (primary key), blockName, createdBy, and delete (boolean)

当用户添加一个新块并提交表单时,我想验证blockName是唯一的。如果它是唯一的,则blockName将存储在数据库中,删除列设置为false。当用户单击删除按钮时,相应行的删除列将更新为true。尽管数据仍保留在数据库中(未被永久删除(,但不应在网页上显示。

这是我目前使用的验证代码:

$validatedValues = $request->validate([
'blockName' => 'required|unique:blocks',
]);

对于删除,这是我实现的代码:

public function destroy($id)
{
$block = Block::find($id);
$block->delete = true;
if ($block->update()) {
return response()->json(['success' => true]);
}
}

我的问题是:我如何确保当Laravel验证blockName为唯一时,它会排除删除列设置为true的记录?如果有任何见解或建议,我将不胜感激。

感谢您的帮助!

谨致问候。

如果尚未在基础数据库表的blockName列上设置唯一条件。然后你可以做下面这样的事情来解决你的问题。

$request->validate([
'blockName' => 'required|unique:blocks,delete,FALSE'
]);

注意:我不太确定这是否是将布尔值传递给验证器的方式。如果使用软删除,下面的代码将完美工作

我建议你实现laravel模型的SoftDeletes特性,让你的生活更简单。这将在表中添加一个deleted_at列。Laravel将自动为您省略其中已删除_at的行。调用模型的普通delete方法只会设置deleted_at字段,不会将其从DB中删除。这将减轻您更新delete列的负担。

如果您选择这样做。验证如下所示。

$request->validate([
'blockName' => 'required|unique:blocks,deleted_at,NULL'
])

您可以创建一个自定义验证规则来包含您的逻辑。

php artisan make:rule UniqueOrDeleted

App\Rules\UniqueOrDeleted.php

<?php
namespace AppRules;
use IlluminateContractsValidationRule;
class UniqueOrDeleted implements Rule
{
/**
* The model we're going to be performing the query against
*
* @var string
*/
private $model;
/**
* Create a new rule instance.
*
* @param string $model
*
* @return void
*/
public function __construct(string $model)
{
$this->model = $model;
}
/**
* Determine if the validation rule passes.
*
* @param  string  $attribute
* @param  mixed  $value
* @return bool
*/
public function passes($attribute, $value)
{
return $this->model::query()
->where($attribute, $value)
->where('delete', true)
->count();
}
/**
* Get the validation error message.
*
* @return string
*/
public function message()
{
return 'The validation error message.';
}
}

然后您可以按如下方式使用它。

$validatedValues = $request->validate([
'blockName' => ['required', new UniqueOrDeleted(Block::class)],
]);

我们提供了一个model作为构造函数参数,以防您想在其他地方使用相同的概念,这意味着您不必硬编码表名或任何东西。您可以进一步理解这个概念,并提供第二个参数,该参数将指定表中delete字段的名称。

您需要这样做:

Rule::unique('blocks', 'blockName')->where(fn ($qry) => $qry->where('delete', 0));

最新更新