Yii2.0 动态模型验证改造,使其支持自定义属性标签
【项目背景】
在提供业务API或者提供业务服务类操作时,往往需要对很多入口参数进行验证。这个时候Yii2.0框架的动态model验证起到了很好的支撑的作用。但是很多参数验证实际同数据库model保存验证类似,希望能够提取到模型的attributeLabels()属性标签进行验证提示。而不是每个字段验证都要定义message提示信息。
【改造步骤】
1、继承覆写yii\base\DynamicModel动态模型中的validateData()方法:
<?php namespace common\ext; use yii\base\DynamicModel; use yii\base\InvalidConfigException; use yii\base\UnknownPropertyException; use yii\helpers\ArrayHelper; use yii\validators\Validator; /** * 拓展动态验证model类,使其支持attributeLabels() * * Class ValidatorModelExt * @package common\ext */ class ValidatorModelExt extends DynamicModel { /** * 属性标签 * * @var array */ private $_attributeLabels = []; /** * {@inheritdoc} */ public function __get($name) { try { if (strpos($name, '.') !== false) { list($prefix, $key) = explode('.', $name, 2); if ($this->hasAttribute($prefix)) { $array = parent::__get($prefix); if (!is_array($array)) { return null; } return ArrayHelper::getValue($array, $key); } else { return parent::__get($name); } } else { return parent::__get($name); } } catch (UnknownPropertyException $e) { return null; } } /** * {@inheritdoc} */ public function __set($name, $value) { if (strpos($name, '.') !== false) { list($prefix, $key) = explode('.', $name, 2); if ($this->hasAttribute($prefix)) { $array = parent::__get($prefix); if (!is_array($array)) { throw new UnknownPropertyException('Setting non array property: ' . get_class($this) . '::' . $name); } ArrayHelper::setValue($array, $key, $value); parent::__set($prefix, $array); } else { parent::__set($name, $value); } } else { parent::__set($name, $value); } } /** * 覆写validateData() method * * @param array $data the data (name-value pairs) to be validated * @param array $rules the validation rules. Please refer to [[Model::rules()]] on the format of this parameter. * @param array $attributeLabels attribute label desc * @return static the model instance that contains the data being validated * @throws InvalidConfigException if a validation rule is not specified correctly. */ public static function validateData(array $data, $rules = [], $attributeLabels = []) { /* @var $model DynamicModel */ $model = new static($data); if (!empty($rules)) { $validators = $model->getValidators(); foreach ($rules as $rule) { if ($rule instanceof Validator) { $validators->append($rule); } elseif (is_array($rule) && isset($rule[0], $rule[1])) { // attributes, validator type // 支持modelClassName对象自动获取attributeLabels属性标签 if (!empty($rule['modelClassName'])) { $modelObj = \Yii::createObject($rule['modelClassName']); if (!empty($modelObj->attributeLabels())) { $attributeLabels = array_merge($attributeLabels, $modelObj->attributeLabels()); } } unset($rule['modelClassName']); // 删除modelClassName避免校验器报错 $validator = Validator::createValidator($rule[1], $model, (array)$rule[0], array_slice($rule, 2)); $validators->append($validator); } else { throw new InvalidConfigException('Invalid validation rule: a rule must specify both attribute names and validator type.'); } } } $model->_attributeLabels = $attributeLabels; // 属性标签赋值 $model->validate(); return $model; } /** * 获取属性标签 * * {@inheritdoc} */ public function attributeLabels() { return $this->_attributeLabels; } }
2、增加ValidatorHelper辅助类为项目提供统一的验证操作(注意:validate()验证方法中使用了上面的ValidatorModelExt拓展类):
<?php namespace common\helpers; use common\ext\ValidatorModelExt; use ts\php\validator\ValidatorModel; use yii\base\UserException; /** * 验证器helper类 * * Class ValidatorHelper * @package common\helpers */ class ValidatorHelper { /** * 动态rules校验,rules请参考Yii2.0 model rules的定义规则 * * @param string|array $data 需要检验的数据 * @param array $rules 定义的rules规则 * @param array $attributeLabels 属性标签描述 注意:也支持在rules中自定义modelClassName参数自动获取model标签属性 * * example: * $rules = [ * [['user_name', 'real_name'], 'required', 'modelClassName' => User::className()], * ]; * * @return bool * @throws \Exception * @throws \yii\base\InvalidConfigException */ public static function validate($data, $rules = [], $attributeLabels = []) { if (empty($rules)) { return true; } $model = ValidatorModelExt::validateData($data, $rules, $attributeLabels); if ($model->hasErrors()) { $error = $model->getErrorSummary(false); throw new \Exception(reset($error)); } return true; } }
【如何使用】
温馨提示:以下两种方式也可以结合使用哦!
方式1、自定义attributeLabels属性标签,然后调用ValidatorHelper::validate()方法,如下图所示:
方式2、在rules规则中定义modelClassName属性,则会自动提取对应模型类attributeLabels()定义的属性标签,如下图所示: