Yii2:如何将属性中的 CSV 字符串映射到表单中的 CheckboxList?
Yii2: How to map a CSV string in an attribute to CheckboxList in a form?
我有一个模型,其属性包含 CSV 字符串。
(该模型实际上是一个ActiveRecord对象,但我想这并不重要。如果我错了请纠正我。)
/**
* @property string $colors Can be something like "red" or "red,green,blue" or ""
*/
class Product extends Model {
}
我有一个表单,我想在其中将此属性显示为 checkboxList,这样用户就可以 select 通过简单的单击而不是在文本输入中键入可能的值。
理论上,它看起来应该类似于:
<?php $availableColors = ['red' => 'Red', 'green' => 'Green', 'blue' => 'Blue']; ?>
<?php $form = ActiveForm::begin([]); ?>
<?= $form->field($model, 'colors')->checkboxList($availableColors) ?>
<?php ActiveForm::end(); ?>
这显然行不通,因为字段 colors
需要是一个数组。但在我的模型中它是一个字符串。
实现该目标的好方法是什么?用JS还是伪属性? colors
属性不得更改,因为它已在不应修改的其他上下文中使用。
我认为这是一个 PHP 问题,但无论如何您都可以使用 PHP explode 来构建您需要的数组。有关详细信息,请参阅 here,然后使用 checkboxList
中的数组
CSV 是一种文件格式,用于在本机以不兼容格式运行的程序之间移动表格数据。将它用作模型属性不是很优雅(说得好听)。在我看来,您应该开始将颜色存储在数组中。
也就是说,您可以使用模型中的 beforeValidate()
函数将数组数据从下拉列表转换为 CSV:
public function beforeValidate() {
$this->colors = explode(';', $this->colors);
return parent::beforeValidate();
}
您可以重写模型中的 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,
]);
}
]) ?>
现在我用一个额外的表单模型解决了这个问题。这在我看来是一个合适的解决方案。
/**
* @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(); ?>
当然,现在controller不得不使用继承模型class。
如果未选中复选框,该解决方案也会处理该问题。这就是引入 'none-value'
的原因。
我有一个模型,其属性包含 CSV 字符串。
(该模型实际上是一个ActiveRecord对象,但我想这并不重要。如果我错了请纠正我。)
/**
* @property string $colors Can be something like "red" or "red,green,blue" or ""
*/
class Product extends Model {
}
我有一个表单,我想在其中将此属性显示为 checkboxList,这样用户就可以 select 通过简单的单击而不是在文本输入中键入可能的值。
理论上,它看起来应该类似于:
<?php $availableColors = ['red' => 'Red', 'green' => 'Green', 'blue' => 'Blue']; ?>
<?php $form = ActiveForm::begin([]); ?>
<?= $form->field($model, 'colors')->checkboxList($availableColors) ?>
<?php ActiveForm::end(); ?>
这显然行不通,因为字段 colors
需要是一个数组。但在我的模型中它是一个字符串。
实现该目标的好方法是什么?用JS还是伪属性? colors
属性不得更改,因为它已在不应修改的其他上下文中使用。
我认为这是一个 PHP 问题,但无论如何您都可以使用 PHP explode 来构建您需要的数组。有关详细信息,请参阅 here,然后使用 checkboxList
中的数组CSV 是一种文件格式,用于在本机以不兼容格式运行的程序之间移动表格数据。将它用作模型属性不是很优雅(说得好听)。在我看来,您应该开始将颜色存储在数组中。
也就是说,您可以使用模型中的 beforeValidate()
函数将数组数据从下拉列表转换为 CSV:
public function beforeValidate() {
$this->colors = explode(';', $this->colors);
return parent::beforeValidate();
}
您可以重写模型中的 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,
]);
}
]) ?>
现在我用一个额外的表单模型解决了这个问题。这在我看来是一个合适的解决方案。
/**
* @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(); ?>
当然,现在controller不得不使用继承模型class。
如果未选中复选框,该解决方案也会处理该问题。这就是引入 'none-value'
的原因。