在 Laravel 9 中,验证字段值在表中的唯一性,不得不将请求输入传递给 ignore 方法的折衷处理
1、请求参数如下,需要确保 logistics_freight_no 在表中的唯一性。由于支持批量覆盖写入,最终的实现方案是先清空 return_order_id 为 28 的所有记录,然后再全部重新写入。
{
"return_order_id": 28,
"data": [
{
"logistics_company": 65656,
"logistics_freight_no": 1
},
{
"logistics_company": 65656,
"logistics_freight_no": 2
}
]
}
2、验证规则实现如下
$validator = Validator::make(
$params,
[
'return_order_id' => [
'required',
'numeric',
'integer',
Rule::exists('Modules\Order\Models\ReturnOrder', 'id')
],
'data' => [
'required',
'array'
],
'data.*.logistics_company' => 'max::255',
'data.*.logistics_freight_no' => [
'required',
'distinct',
'max::255',
Rule::unique('Modules\Order\Models\ReturnOrderLogistic'),
]
],
[
'return_order_id.required' => '请选择退货订单ID',
'return_order_id.numeric' => '退货订单ID必须是数字',
'return_order_id.integer' => '退货订单ID必须是整数',
'return_order_id.exists' => '退货订单ID不存在',
'data.required' => '请填写退货订单物流信息',
'data.array' => '退货订单物流信息必须是数组',
'data.*.logistics_company.max' => '物流公司最大长度是255',
'data.*.logistics_freight_no.required' => '请填写货运单号',
'data.*.logistics_freight_no.distinct' => '货运单号不允许重复',
'data.*.logistics_freight_no.max' => '货运单号最大长度是255',
'data.*.logistics_freight_no.unique' => '货运单号已被占用'
]
);
3、当表中 logistics_freight_no 存在重复值时,验证失败,提示:货运单号已被占用。如图1
4、参考:强制唯一规则忽略给定 ID 。但是,注意:你不应该将任何用户控制的请求输入传递给 ignore 方法。相反,您应该只传递系统生成的唯一 ID,例如来自 Eloquent 模型实例的自动递增 ID 或 UUID。否则,您的应用程序将容易受到 SQL 注入攻击。不得不将请求输入 return_order_id 传递给 ignore 方法,不过可以提前验证 return_order_id 是否是 Eloquent 模型实例的自动递增 ID。为了防止 SQL 注入攻击,决定强制转换为 int 类型
$validator = Validator::make(
$params,
[
'return_order_id' => [
'required',
'numeric',
'integer',
Rule::exists('Modules\Order\Models\ReturnOrder', 'id')
],
'data' => [
'required',
'array'
],
'data.*.logistics_company' => 'max::255',
'data.*.logistics_freight_no' => [
// 如果退货订单ID不存在,则不验证,防止报错:Undefined array key "return_order_id"
'exclude_without:return_order_id',
'required',
'distinct',
'max::255',
Rule::unique('Modules\Order\Models\ReturnOrderLogistic')->ignore((int)$params['return_order_id'], 'return_order_id')
]
],
[
'return_order_id.required' => '请选择退货订单ID',
'return_order_id.numeric' => '退货订单ID必须是数字',
'return_order_id.integer' => '退货订单ID必须是整数',
'return_order_id.exists' => '退货订单ID不存在',
'data.required' => '请填写退货订单物流信息',
'data.array' => '退货订单物流信息必须是数组',
'data.*.logistics_company.max' => '物流公司最大长度是255',
'data.*.logistics_freight_no.required' => '请填写货运单号',
'data.*.logistics_freight_no.distinct' => '货运单号不允许重复',
'data.*.logistics_freight_no.max' => '货运单号最大长度是255',
'data.*.logistics_freight_no.unique' => '货运单号已被占用'
]
);
5、当第一次请求成功后,第二次请求虽然有重复的 logistics_freight_no ,仍然可以请求成功。最终执行的 SQL 如下,符合预期
{
"return_order_id": 28,
"data": [
{
"logistics_company": 65656,
"logistics_freight_no": 1
},
{
"logistics_company": 65656,
"logistics_freight_no": 2
},
{
"logistics_company": 65656,
"logistics_freight_no": 24
}
]
}
select count(*) as aggregate from `return_orders` where `id` = 28
select
count(*) as aggregate
from
`return_order_logistics`
where
`logistics_freight_no` = 1
and `return_order_id` <> '28'
select
count(*) as aggregate
from
`return_order_logistics`
where
`logistics_freight_no` = 2
and `return_order_id` <> '28'
select
count(*) as aggregate
from
`return_order_logistics`
where
`logistics_freight_no` = 24
and `return_order_id` <> '28'
delete from `return_order_logistics` where `return_order_id` = 28
insert into
`return_order_logistics` (
`created_at_gmt`,
`logistics_company`,
`logistics_freight_no`,
`return_order_id`,
`updated_at_gmt`
)
values
(
'2024-04-25 02:23:41',
65656,
1,
28,
'2024-04-25 02:23:41'
),
(
'2024-04-25 02:23:41',
65656,
2,
28,
'2024-04-25 02:23:41'
),
(
'2024-04-25 02:23:41',
65656,
24,
28,
'2024-04-25 02:23:41'
)
6、那么当 return_order_id 不为 28 时,验证失败:货运单号已被占用,符合预期。执行 SQL 如下
{
"return_order_id": 29,
"data": [
{
"logistics_company": 65656,
"logistics_freight_no": 1
},
{
"logistics_company": 65656,
"logistics_freight_no": 2
},
{
"logistics_company": 65656,
"logistics_freight_no": 24
}
]
}
{
"status_code": 400,
"code": -1,
"message": "货运单号已被占用"
}
select count(*) as aggregate from `return_orders` where `id` = 29 select count(*) as aggregate from `return_order_logistics` where `logistics_freight_no` = 1 and `return_order_id` <> '29'

近期评论