项目中常遇到枚举类型字段的显示问题,如类型、状态等,这些字段在列表页、详情页以及表单页通常需要特殊处理,增加一个类型或状态,要修改所有的视图,这显然不合理,为解决这个问题,可以对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~~