必须显式配置 targetclass,否则 unique 验证器因 class not found 而静默失效,不报“重复”错误;还需设 targetattribute 映射字段、建数据库唯一索引,并在 ajax 校验时限定字段避免验证码干扰。

唯一校验必须显式配置 targetClass,否则 unique 验证器会直接报 Class not found 错误,而不是“重复”提示。
unique 验证器不生效?先确认 targetClass 是否指定
unique 验证器默认在当前模型类里找 findByEmail() 这类方法,但表单模型(如 SignupForm)没有数据库表,也不会有这些方法——框架找不到类就抛出 Class not found,而不是去查数据库。你看到的“验证通过”,很可能是验证根本没跑起来。
- 必须加
'targetClass' => '\app\models\User',指向实际带数据表的 ActiveRecord 类 - 如果字段名和数据库列名不一致(比如模型属性叫
email,但表里是user_email),还得补'targetAttribute' => ['user_email' => 'email'] - 不写
targetClass时,validate()可能静默返回true,脏数据直接入库
AJAX 实时校验重复项,要限定字段避免干扰验证码
开启 enableAjaxValidation 后,ActiveForm::validate($model) 默认校验所有字段,包括验证码。而验证码验证会重置 session 中的 code,导致提交时必错。
- 控制器中不要直接写
ActiveForm::validate($model) - 改用
ActiveForm::validate($model, ['username', 'email']),只传需要去重的字段名数组 - 前端每个字段单独开 AJAX 验证更稳妥:
= $form->field($model, 'username', ['enableAjaxValidation' => true]) ?> - 后端 AJAX 入口必须在
$model->load()之后、isAjax判断之前执行,否则load()失败导致空模型校验
数据库索引缺失会导致 unique 查询变全表扫描
unique 验证底层是 SQL SELECT COUNT(*) 查询,没索引时大表上会严重拖慢响应,高并发下还可能引发死锁。
- 对用于
unique校验的字段(如email、username),必须在数据库建唯一索引或普通索引 - 用
yii migrate添加索引比手动执行 SQL 更安全:$this->createIndex('idx-user-email', 'user', 'email', true) - 如果字段组合去重(如
['email', 'status']),索引必须覆盖全部字段且顺序一致
最常被忽略的是:targetClass 缺失时错误不报在验证层,而是卡在反射类加载阶段;你看到的“没报错”,其实是验证压根没触发。











