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

Laravel中如何基于年月与数字列实现联合唯一验证

解决Laravel中deed_number与年月唯一的验证问题

我来帮你搞定这个需求——你需要实现的是当同一个年月(YYYY-MM)下出现重复的deed_number时触发验证错误,而不是当前的完整日期(YYYY-MM-DD)验证。下面是具体的实现方案:

第一步:优化数据库日期字段(推荐)

你的迁移里date字段用了string类型,虽然也能处理,但改成date类型更符合数据库设计规范,也更方便后续日期操作。如果你的项目还没上线,可以直接修改原迁移文件;如果已经上线,创建一个新的迁移来修改字段:

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ChangeDateToDateTypeInDeedNotaryNumbersTable extends Migration
{
    public function up()
    {
        Schema::table('deed_notary_numbers', function (Blueprint $table) {
            // 确保字段值都是合法的Y-m-d格式再执行此操作
            $table->date('date')->change();
        });
    }

    public function down()
    {
        Schema::table('deed_notary_numbers', function (Blueprint $table) {
            $table->string('date')->change();
        });
    }
}

执行迁移:

php artisan migrate

第二步:实现年月+deed_number的唯一验证

这里提供两种方案,你可以根据自己的习惯选择:

方案一:使用Laravel自带的Rule类(更简洁)

直接在表单验证规则中使用Rule::unique()并添加自定义查询条件,匹配年月和deed_number:

首先在你的表单所在文件顶部引入依赖:

use Illuminate\Validation\Rule;
use Carbon\Carbon;

然后修改表单的验证规则:

$form->number('deed_number', 'Nomor Akta')
    ->placeholder('Nomor Akta')
    ->creationRules([
        'required',
        Rule::unique('deed_notary_numbers')->where(function ($query) use ($request) {
            // 提取日期的年月部分
            $yearMonth = Carbon::parse($request->date)->format('Y-m');
            // 匹配年月和deed_number
            return $query->whereRaw("DATE_FORMAT(date, '%Y-%m') = ?", [$yearMonth])
                         ->where('deed_number', $request->deed_number);
        })
    ])
    ->updateRules([
        'required',
        Rule::unique('deed_notary_numbers')->ignore($this->id)->where(function ($query) use ($request) {
            $yearMonth = Carbon::parse($request->date)->format('Y-m');
            return $query->whereRaw("DATE_FORMAT(date, '%Y-%m') = ?", [$yearMonth])
                         ->where('deed_number', $request->deed_number);
        })
    ]);

$form->date('date', 'Tanggal Akta')
    ->placeholder('Tgl Akta')
    ->rules('required');

方案二:自定义验证规则类(更易复用)

如果这个验证规则需要在多个地方使用,创建自定义规则类会更合适:

  1. 创建规则文件app/Rules/UniqueMonthDate.php:
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class UniqueMonthDate implements Rule
{
    protected $ignoreId;

    // 构造方法接收要忽略的ID(更新时用)
    public function __construct($ignoreId = null)
    {
        $this->ignoreId = $ignoreId;
    }

    public function passes($attribute, $value)
    {
        $date = request()->input('date');
        $yearMonth = Carbon::parse($date)->format('Y-m');

        $query = DB::table('deed_notary_numbers')
            ->whereRaw("DATE_FORMAT(date, '%Y-%m') = ?", [$yearMonth])
            ->where('deed_number', $value);

        // 更新时忽略当前记录
        if ($this->ignoreId) {
            $query->where('id', '!=', $this->ignoreId);
        }

        // 检查是否存在重复记录
        return $query->count() === 0;
    }

    public function message()
    {
        return 'Nomor Akta sudah ada di bulan yang sama.'; // 自定义错误提示
    }
}
  1. 在表单中使用这个规则:
// 顶部引入规则类
use App\Rules\UniqueMonthDate;

$form->number('deed_number', 'Nomor Akta')
    ->placeholder('Nomor Akta')
    ->creationRules(['required', new UniqueMonthDate()])
    ->updateRules(['required', new UniqueMonthDate($this->id)]);

$form->date('date', 'Tanggal Akta')
    ->placeholder('Tgl Akta')
    ->rules('required');

验证效果

这样设置后,当你输入:

  • deed_number=3 + date=2019-10-19 → 允许
  • deed_number=3 + date=2019-10-20 → 触发验证错误,无法存入数据库
    完全符合你的需求~

内容的提问来源于stack exchange,提问作者vreedom18

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:20:27