zoukankan      html  css  js  c++  java
  • Yii2.0 动态模型验证改造,使其支持自定义属性标签

    【项目背景】

    在提供业务API或者提供业务服务类操作时,往往需要对很多入口参数进行验证。这个时候Yii2.0框架的动态model验证起到了很好的支撑的作用。但是很多参数验证实际同数据库model保存验证类似,希望能够提取到模型的attributeLabels()属性标签进行验证提示。而不是每个字段验证都要定义message提示信息。

    【改造步骤】

    1、继承覆写yiiaseDynamicModel动态模型中的validateData()方法:

    <?php
    
    namespace commonext;
    
    use yiiaseDynamicModel;
    use yiiaseInvalidConfigException;
    use yiiaseUnknownPropertyException;
    use yiihelpersArrayHelper;
    use yiivalidatorsValidator;
    
    /**
     * 拓展动态验证model类,使其支持attributeLabels()
     *
     * Class ValidatorModelExt
     * @package commonext
     */
    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 commonhelpers;
    
    use commonextValidatorModelExt;
    use tsphpvalidatorValidatorModel;
    use yiiaseUserException;
    
    /**
     * 验证器helper类
     *
     * Class ValidatorHelper
     * @package commonhelpers
     */
    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 yiiaseInvalidConfigException
         */
        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()定义的属性标签,如下图所示:

  • 相关阅读:
    网络流24题之 1738: 最小路径覆盖问题
    POJ 1966 Cable TV Network
    网络流24题- 魔术球问题
    网络流24题之 圆桌问题
    可持久化线段树维护启发式合并的可持久化并查集
    HDU 6166 Senior Pan
    ACM对拍cpp程序
    双联通分量复习
    欧拉回路求路径POJ 2230
    LCA的两种求法
  • 原文地址:https://www.cnblogs.com/itsharehome/p/12276073.html
Copyright © 2011-2022 走看看