OctoberCMS中如何基于父分类设置子分类名称的联合唯一校验?
同维度复合唯一校验实现说明
该需求完全可实现,之前参考的通用方案不生效,核心原因是OctoberCMS的模型校验机制和原生Laravel表单校验的触发逻辑存在差异,静态写死的规则无法适配「动态关联父分类ID、自动排除当前编辑记录」两个核心场景。
核心规则逻辑
OctoberCMS底层基于Laravel校验体系,unique校验规则支持附加多维度查询条件,完整参数结构为:unique:数据表名称,校验字段名,需要排除的记录主键值,主键字段名,附加筛选字段1,附加筛选值1,...
只要在原有全局唯一规则的基础上,把当前提交的category_id作为附加筛选条件传入,同时加上更新场景下的自身记录排除逻辑,就能实现「同一父分类下子分类名唯一、跨父分类同名放行」的效果。
全场景兼容的实现代码
不要把校验规则完全固定在模型的静态$rules属性中,重写模型的beforeValidate钩子方法,在每次校验触发前动态生成匹配当前场景的规则即可:
// 子分类模型类中添加如下方法 public function beforeValidate() { // 获取当前模型对应的数据表名 $table = $this->table; // 获取当前正在编辑/提交的父分类ID $submittedCategoryId = $this->category_id; // 更新场景下排除当前记录自身,避免编辑时误报重复 $excludePrimaryKey = $this->exists ? $this->getKey() : 'NULL'; // 动态拼接生成唯一校验规则 $this->rules['name'] = sprintf( 'required|unique:%s,name,%s,id,category_id,%s', $table, $excludePrimaryKey, $submittedCategoryId ); }
规则生效逻辑说明
拼接完成的规则会自动完成以下判断:
- 新增场景:在数据表中查找同时满足「name值和当前提交的子分类名一致」「category_id和当前选择的父分类ID一致」的记录,如果存在则触发重复提示
- 更新场景:在上述判断的基础上,额外排除当前正在编辑的这条记录本身,避免用户仅修改其他字段、不改动子分类名时,系统误判为重复
- 跨父分类场景:只要两条同名子分类分属不同的父分类ID,查询时不会命中,自然不会触发校验拦截
高频踩坑提醒
- 不要在静态
$rules数组中硬写固定的附加筛选值,比如unique:xxx,name,NULL,id,category_id,1这类把父分类ID写死的配置,会导致校验仅对Category 1生效,选择Category 2时完全不触发校验 - 注意主键字段的匹配:如果你的子分类表主键不是默认的
id字段,要把规则中对应的主键字段名替换为实际的字段值,不要默认沿用id - 父分类筛选条件要匹配数据表的实际存储字段名,不要写关联关系的方法名(比如关联方法是
parent,但实际存储关联值的字段是category_id,规则里就必须写category_id)
内容的提问来源于stack exchange,提问作者Mittul At TechnoBrave
相关产品推荐
相关产品推荐

