Laravel 8 实现跨companies、units两张表的cnpj字段唯一性验证
Laravel 8 跨双表唯一校验实现方案
方案1:闭包验证规则(适合一次性场景)
直接在验证规则中传入闭包,编写两张表的校验逻辑:
Store 新增场景代码
$rules = [ 'cnpj' => [ 'required', 'string', function ($attribute, $value, $fail) { // 校验企业表无重复 if (\App\Models\Company::where('cnpj', $value)->exists()) { $fail('该CNPJ已在企业表中存在,不可重复使用'); } // 校验单元表无重复 if (\App\Models\Unit::where('cnpj', $value)->exists()) { $fail('该CNPJ已在单元表中存在,不可重复使用'); } }, ] ];
Update 更新场景代码
以编辑企业表记录为例,需要排除当前编辑的企业ID,同时校验单元表全表:
$rules = [ 'cnpj' => [ 'required', 'string', function ($attribute, $value, $fail) { // 排除当前正在编辑的企业记录 if (\App\Models\Company::where('cnpj', $value)->where('id', '!=', $this->company->id)->exists()) { $fail('该CNPJ已在其他企业中存在,不可重复使用'); } // 单元表全表校验无重复 if (\App\Models\Unit::where('cnpj', $value)->exists()) { $fail('该CNPJ已在单元表中存在,不可重复使用'); } }, ] ];
如果编辑的是单元表记录,只需反过来排除当前单元ID,校验企业表全表即可。
方案2:自定义全局验证规则(适合多场景复用)
如果多个接口都需要用到跨表CNPJ校验,可以封装为独立规则类,复用性更高:
- 执行命令生成规则类:
php artisan make:rule UniqueCnpj
- 编辑
app/Rules/UniqueCnpj.php文件逻辑:
namespace App\Rules; use Illuminate\Contracts\Validation\Rule; use App\Models\Company; use App\Models\Unit; class UniqueCnpj implements Rule { protected $ignoreId; protected $ignoreTable; // 更新场景传入要排除的资源ID和对应表名,新增场景无需传参 public function __construct($ignoreId = null, $ignoreTable = null) { $this->ignoreId = $ignoreId; $this->ignoreTable = $ignoreTable; } public function passes($attribute, $value) { // 校验企业表 $companyQuery = Company::where('cnpj', $value); if ($this->ignoreTable === 'companies' && $this->ignoreId) { $companyQuery->where('id', '!=', $this->ignoreId); } if ($companyQuery->exists()) return false; // 校验单元表 $unitQuery = Unit::where('cnpj', $value); if ($this->ignoreTable === 'units' && $this->ignoreId) { $unitQuery->where('id', '!=', $this->ignoreId); } if ($unitQuery->exists()) return false; return true; } public function message() { return '该CNPJ已存在,不可重复使用'; } }
- 不同场景调用方式:
- 新增场景:
'cnpj' => ['required', 'string', new \App\Rules\UniqueCnpj()],
- 更新企业记录场景:
'cnpj' => ['required', 'string', new \App\Rules\UniqueCnpj($this->company->id, 'companies')],
- 更新单元记录场景:
'cnpj' => ['required', 'string', new \App\Rules\UniqueCnpj($this->unit->id, 'units')],
直接拼接两个unique规则不生效的原因
如果是更新场景,你只排除了当前操作表的记录ID,另一张表的unique规则没有做对应逻辑处理,或者你编辑的是单元表记录,但仅写了企业表的排除逻辑,就会出现校验失效的问题。
内容的提问来源于stack exchange,提问作者Mauricio
相关产品推荐
相关产品推荐

