我有一个模型,其属性包含 CSV 字符串。
(该模型实际上是一个 ActiveRecord 对象,但我想这并不重要。如果我错了,请纠正我。)
/**
* @property string $colors Can be something like "red" or "red,green,blue" or ""
*/
class Product extends Model {
}
我有一个表单,我想在其中将此属性显示为 checkboxList ,以便用户可以通过简单的单击来选择可能的值,而不是在文本输入中键入。
理论上,它应该类似于这样:
<?php $availableColors = ['red' => 'Red', 'green' => 'Green', 'blue' => 'Blue']; ?>
<?php $form = ActiveForm::begin([]); ?>
<?= $form->field($model, 'colors')->checkboxList($availableColors) ?>
<?php ActiveForm::end(); ?>
这显然不起作用,因为字段
colors
需要是一个数组。但在我的模型中它是一个字符串。
实现这一目标的好方法是什么?用JS还是伪属性?
colors
属性不得更改,因为它已在其他不应修改的上下文中使用。
您可以重写模型中的
beforeValidate
方法,将 implode
颜色数组转换为字符串。在您看来,您可以使用以下内容:
<?= $form->field($model, 'colors')->checkboxList($availableColors,
[
'item'=> function ($index, $label, $name, $checked, $value) use ($model) {
$colors = explode(';', $model->colors);
$checked = in_array($value, $colors);
return Html::checkbox($name, $checked, [
'value' => $value,
'label' => $label,
]);
}
]) ?>
CSV 是一种文件格式,用于在本机以不兼容格式运行的程序之间移动表格数据。使用它作为模型属性并不是很优雅(说得好听一点)。在我看来,您应该开始将颜色存储在数组中。
话虽这么说,您可以使用模型中的
beforeValidate()
函数将下拉列表中的数组数据转换为 CSV:
public function beforeValidate() {
$this->colors = explode(';', $this->colors);
return parent::beforeValidate();
}
我认为这是一个 PHP 问题,但无论如何你可以使用 PHP Explode 来构建你需要的数组。请参阅 here 了解更多详细信息,然后使用 checkboxList 中的数组
现在我用表单的额外模型解决了这个问题。在我看来,这是一个正确的解决方案。
/**
* @property string $colors Can be something like "red" or "red,green,blue" or ""
*/
class Product extends Model {
}
/**
* @property string[] $colorsAsArray
*/
class ProductForm extends Product {
public function rules() {
return array_merge(parent::rules(), [
['colorsAsArray', 'safe'] // just to make it possible to use load()
]);
}
public function getColorsAsArray() {
return explode(',', $this->colors);
}
public function setColorsAsArray($value) {
$this->colors = self::implode($value);
}
protected static function implode($value) {
if ($value == 'none-value') return '';
return implode(',', $value);
}
/* - - - - - - - - - - optional - - - - - - - - - - */
public function attributeLabels() {
$attributeLabels = parent::attributeLabels();
return array_merge($attributeLabels, [
'colorsAsArray' => $attributeLabels['colors'],
]);
}
}
这样我就可以这样使用表格了:
<?php $availableColors = ['red' => 'Red', 'green' => 'Green', 'blue' => 'Blue']; ?>
<?php $form = ActiveForm::begin([]); ?>
<?= $form->field($model, 'colorsAsArray')
->checkboxList($availableColors, ['unselect' => 'none-value']) ?>
<?php ActiveForm::end(); ?>
当然,现在控制器必须使用继承的模型类。
如果未选中任何复选框,该解决方案也可以解决该问题。这就是引入
'none-value'
的原因。