You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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校验,可以封装为独立规则类,复用性更高:

  1. 执行命令生成规则类:
php artisan make:rule UniqueCnpj
  1. 编辑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已存在,不可重复使用';
    }
}
  1. 不同场景调用方式:
  • 新增场景:
'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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 15:45:09