a6297416 2016-12-04 09:58:28 4301次浏览 1条回复 0 0 0

项目中常遇到枚举类型字段的显示问题,如类型、状态等,这些字段在列表页、详情页以及表单页通常需要特殊处理,增加一个类型或状态,要修改所有的视图,这显然不合理,为解决这个问题,可以对Yii框架进行优化,后续只需维护模型即可,以下是代码实现:

1、修改Yii基础模型类:

yii\base\Model,新增attributeValues方法

/**
     * Returns the attribute values.
     *
     * Attribute values are mainly used for display purpose. For example, given an attribute
     * `status`, we can declare a value `Active` when `status` equal 1, which is more user-friendly and can
     * be displayed to end users.
     *
     * Note, in order to inherit values defined in the parent class, a child class needs to
     * merge the parent values with child values using functions such as `array_merge()`.
     *
     * @return array attribute values (name => ['key1'=>'value1','key2'=>'value2'])
     * @see generateAttributeValue()
     */
    public function attributeValues()
    {
    	return [];
    }

2、修改列表页获取数据单元值方法:

yii\grid\DataColumn,修改getDataCellValue方法

/**
     * Returns the data cell value.
     * @param mixed $model the data model
     * @param mixed $key the key associated with the data model
     * @param integer $index the zero-based index of the data model among the models array returned by [[GridView::dataProvider]].
     * @return string the data cell value
     */
    public function getDataCellValue($model, $key, $index)
    {
        if ($this->value !== null) {
            if (is_string($this->value)) {
                return ArrayHelper::getValue($model, $this->value);
            } else {
                return call_user_func($this->value, $model, $key, $index, $this);
            }
        } elseif ($this->attribute !== null) {
        	$value = ArrayHelper::getValue($model, $this->attribute);
        	if ($model instanceof Model) {
        		$attributeValues = $model->attributeValues();
        		if (!empty($attributeValues) && ArrayHelper::keyExists($this->attribute, $attributeValues) && is_array($attributeValues[$this->attribute]) && ArrayHelper::keyExists($value,$attributeValues[$this->attribute])) {
        			return $attributeValues[$this->attribute][$value];
        		} else {
        			return $value;
        		}
        	} else {
        		return $value;
        	}
        }
        return null;
    }

3、修改详情页标准化属性方法:

yii\widgets\DetailView,修改normalizeAttributes方法

/**
     * Normalizes the attribute specifications.
     * @throws InvalidConfigException
     */
    protected function normalizeAttributes()
    {
        if ($this->attributes === null) {
            if ($this->model instanceof Model) {
                $this->attributes = $this->model->attributes();
            } elseif (is_object($this->model)) {
                $this->attributes = $this->model instanceof Arrayable ? array_keys($this->model->toArray()) : array_keys(get_object_vars($this->model));
            } elseif (is_array($this->model)) {
                $this->attributes = array_keys($this->model);
            } else {
                throw new InvalidConfigException('The "model" property must be either an array or an object.');
            }
            sort($this->attributes);
        }

        foreach ($this->attributes as $i => $attribute) {
            if (is_string($attribute)) {
                if (!preg_match('/^([\w\.]+)(:(\w*))?(:(.*))?$/', $attribute, $matches)) {
                    throw new InvalidConfigException('The attribute must be specified in the format of "attribute", "attribute:format" or "attribute:format:label"');
                }
                $attribute = [
                    'attribute' => $matches[1],
                    'format' => isset($matches[3]) ? $matches[3] : 'text',
                    'label' => isset($matches[5]) ? $matches[5] : null,
                ];
            }

            if (!is_array($attribute)) {
                throw new InvalidConfigException('The attribute configuration must be an array.');
            }

            if (isset($attribute['visible']) && !$attribute['visible']) {
                unset($this->attributes[$i]);
                continue;
            }

            if (!isset($attribute['format'])) {
                $attribute['format'] = 'text';
            }
            if (isset($attribute['attribute'])) {
                $attributeName = $attribute['attribute'];
                if (!isset($attribute['label'])) {
                    $attribute['label'] = $this->model instanceof Model ? $this->model->getAttributeLabel($attributeName) : Inflector::camel2words($attributeName, true);
                }
                if (!array_key_exists('value', $attribute)) {
                	$value = ArrayHelper::getValue($this->model, $attributeName);
                	if ($this->model instanceof Model) {
                		$attributeValues = $this->model->attributeValues();
                		if (!empty($attributeValues) && ArrayHelper::keyExists($attribute['attribute'], $attributeValues) && is_array($attributeValues[$attribute['attribute']]) && ArrayHelper::keyExists($value,$attributeValues[$attribute['attribute']])) {
                			$attribute['value'] = $attributeValues[$attribute['attribute']][$value];
                		} else {
                			$attribute['value'] = $value;
                		}
                	} else {
                		$attribute['value'] = $value;
                	}
                }
            } elseif (!isset($attribute['label']) || !array_key_exists('value', $attribute)) {
                throw new InvalidConfigException('The attribute configuration requires the "attribute" element to determine the value and display label.');
            }

            $this->attributes[$i] = $attribute;
        }
    }

4、修改下拉框部件,选项设定

yii\widgets\ActiveField,修改dropDownList方法(checkboxList、listBox、radioList同)

/**
     * Renders a drop-down list.
     * The selection of the drop-down list is taken from the value of the model attribute.
     * @param array $items the option data items. The array keys are option values, and the array values
     * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too).
     * For each sub-array, an option group will be generated whose label is the key associated with the sub-array.
     * If you have a list of data models, you may convert them into the format described above using
     * [[ArrayHelper::map()]].
     *
     * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
     * the labels will also be HTML-encoded.
     * @param array $options the tag options in terms of name-value pairs.
     *
     * For the list of available options please refer to the `$options` parameter of [[\yii\helpers\Html::activeDropDownList()]].
     *
     * If you set a custom `id` for the input element, you may need to adjust the [[$selectors]] accordingly.
     *
     * @return $this the field object itself.
     */
    public function dropDownList($items = [], $options = [])
    {
    	if (empty($items)) {
    		$attributeValues = $this->model->attributeValues();
    		if (!empty($attributeValues) && ArrayHelper::keyExists($this->attribute, $attributeValues)) {
    			$items = $attributeValues[$this->attribute];
    		}
    	}
        $options = array_merge($this->inputOptions, $options);
        $this->adjustLabelFor($options);
        $this->parts['{input}'] = Html::activeDropDownList($this->model, $this->attribute, $items, $options);

        return $this;
    }
现在就可以在业务模型类中添加attributeValues方法,以一个游戏任务类为例:
<?php

namespace app\models;

use Yii;

/**
 * This is the model class for table "{{%task}}".
 *
 */
class Task extends yii\db\ActiveRecord
{
    /**
     * (non-PHPdoc)
     * @see \yii\base\Model::attributeValues()
     */
    public function attributeValues()
    {
    	return [
    		'type' => [
    			'0' => '新手任务',
    			'1' => '每日任务',
    			'2' => '活动任务',
    		],
    		'status' => [
    			'0' => '暂停',
    			'1' => '正常',
    		],
    	];
    }
}

表单页:

<?= $form->field($model, 'status')->dropDownList() ?>
<?= $form->field($model, 'type')->radioList() ?>

列表页和详情页无需特殊处理。

总结一下:

这么做的好处主要是一点,后续只需要修改模型,提升效率 O(∩_∩)O~~

  • 回复于 2016-12-05 15:43 举报

    有必要这么复杂吗?在相应的 model 添加枚举数组,添加两个方法, getValueText, getValueGroup。需要的时候调用两个方法即可。

您需要登录后才可以回复。登录 | 立即注册