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');
方案二:自定义验证规则类(更易复用)
如果这个验证规则需要在多个地方使用,创建自定义规则类会更合适:
- 创建规则文件
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.'; // 自定义错误提示 } }
- 在表单中使用这个规则:
// 顶部引入规则类 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
相关产品推荐
相关产品推荐

