Laravel Filament中Repeater内同课程Unit名称唯一性校验方案
解决方案
1. 数据库层面添加联合唯一约束(兜底)
首先在units表上创建course_id和name的联合唯一索引,确保即使表单校验失效,数据库也会阻止重复数据:
// 可创建新迁移文件执行该操作 Schema::table('units', function (Blueprint $table) { $table->unique(['course_id', 'name']); });
2. Filament表单层面实现双维度校验
在CourseResource的Wizard第三步Repeater组件中,对Unit的name字段同时做当前Repeater内部的唯一性校验和数据库中同一Course下的唯一性校验,兼容创建和编辑场景:
use Illuminate\Validation\Rules\Unique; use Filament\Forms\Components\Repeater; use Filament\Forms\Components\TextInput; use Filament\Forms\Components\Wizard; public static function form(Form $form): Form { return $form ->schema([ // 前两步的Course基础字段配置... Wizard\Step::make('管理课程单元') ->schema([ Repeater::make('units') ->relationship() ->schema(function (Form $form) { // 获取当前Course模型(编辑时为已存在实例,创建时为新实例) $course = $form->getRecord(); return [ TextInput::make('name') ->label('单元名称') ->required() // 校验当前Repeater内的单元名称不重复 ->unique(ignoreRecord: true) // 校验数据库中同一课程下的单元名称不重复 ->unique(Unit::class, 'name', ignoreRecord: true, modifyRuleUsing: function (Unique $rule) use ($course) { // 编辑场景:课程已存在,添加course_id筛选条件 if ($course->exists) { return $rule->where('course_id', $course->id); } // 创建场景:课程尚未保存,数据库中无该课程的单元,仅需保证Repeater内部不重复 return $rule; }) ]; }) ]), ]); }
关键逻辑说明
- 编辑场景:当编辑已有Course时,
$course->exists为true,通过modifyRuleUsing给Unique规则添加where('course_id', $course->id),确保当前编辑的Unit名称不会与同一Course下的其他已存在Unit重复。 - 创建场景:当创建新Course时,
$course->exists为false,此时数据库中还不存在该Course的任何Unit,仅通过->unique(ignoreRecord: true)确保当前Repeater内的Unit名称不重复,待Course保存后,数据库的联合唯一索引会进一步兜底。 - Repeater内部校验:
->unique(ignoreRecord: true)会自动检查当前Repeater中其他项的name是否重复,无需额外逻辑。
内容的提问来源于stack exchange,提问作者zacktagnan
相关产品推荐
相关产品推荐

