Yii2自定义验证器可校验对象属性,需重写validateAttribute()并用addError()报错;示例ValidCustomerValidator校验Order对象的customer是否为启用状态的Customer实例,支持配置选项与多场景。

Yii2 中自定义验证器可用于校验任意类型参数,包括对象(如模型实例、DTO 对象、stdClass 或自定义类)。关键在于重写 validateAttribute() 方法,并在其中对传入的属性值(即对象)进行逻辑判断,同时正确调用 $this->addError() 添加错误。
定义一个校验对象属性的自定义验证器
假设有一个订单对象 Order,需校验其 customer 属性是否为有效的 Customer 实例,且客户状态为启用:
namespace app\validators;
use yii\validators\Validator;
use app\models\Customer;
use app\models\Order;
class ValidCustomerValidator extends Validator
{
public function validateAttribute($model, $attribute)
{
$value = $model->$attribute;
// 检查是否为 Order 对象(可选,增强健壮性)
if (!$value instanceof Order) {
$this->addError($model, $attribute, '订单对象格式不正确。');
return;
}
$customer = $value->customer;
if (!$customer instanceof Customer) {
$this->addError($model, $attribute, '客户信息缺失或格式错误。');
return;
}
if ($customer->status !== Customer::STATUS_ACTIVE) {
$this->addError($model, $attribute, '客户当前不可用,请检查状态。');
}
}
}
在模型中使用该验证器校验对象属性
在目标模型(如 PaymentForm)中声明一个对象属性,并绑定验证器:
namespace app\models;
use yii\base\Model;
use app\validators\ValidCustomerValidator;
class PaymentForm extends Model
{
public $order; // 接收一个 Order 对象
public function rules()
{
return [
[['order'], ValidCustomerValidator::class],
// 其他规则...
];
}
}
控制器中接收并验证:
$form = new PaymentForm();
$form->order = $orderInstance; // 传入 Order 对象
if ($form->validate()) {
// 验证通过
} else {
// $form->getErrors() 可获取错误信息
}
支持配置选项与多场景校验
可扩展验证器以支持灵活配置,例如允许跳过状态检查、指定客户类名等:
class ValidCustomerValidator extends Validator
{
public $requireActive = true;
public $customerClass = Customer::class;
public function validateAttribute($model, $attribute)
{
$order = $model->$attribute;
if (!$order instanceof Order) {
$this->addError($model, $attribute, '必须传入有效的 Order 对象。');
return;
}
$customer = $order->customer;
$class = $this->customerClass;
if (!$customer instanceof $class) {
$this->addError($model, $attribute, "客户必须是 {$class} 类型。");
return;
}
if ($this->requireActive && $customer->status !== $class::STATUS_ACTIVE) {
$this->addError($model, $attribute, '客户未启用,无法处理支付。');
}
}
}
使用时可传参:
return [
[['order'], ValidCustomerValidator::class, 'requireActive' => false],
];
注意事项与最佳实践
- 确保对象属性在验证前已赋值,Yii 不会自动实例化对象
- 避免在验证器中做耗时操作(如 DB 查询),如需查库建议提前加载好关联数据
- 若校验逻辑复杂,可将核心判断抽离为独立服务方法,保持验证器轻量
- 错误消息建议使用
Yii::t()实现国际化,而非硬编码字符串 - 测试时注意覆盖空对象、非预期类型、null 值等边界情况


















