复选框 HTML 数组语法在 CakePHP 4 中不起作用

Checkbox HTML array syntax doesn't work in CakePHP 4

我在 CakePHP 4 中有一个应用程序,我正在做与 Make array from checkbox form

中描述的等效的事情

我的标记很简单:

<input type="checkbox" name="services[]" value="Service 1" id="service1">
<input type="checkbox" name="services[]" value="Service 2" id="service2">
<input type="checkbox" name="services[]" value="Service 3" id="service3">

所以有人可以例如检查“服务 1”和“服务 3”并省略“服务 2”,例如

我使用 CakePHP 中的表单助手来生成上面的 HTML。代码看起来像这样,并且在该页面的模板文件中:

<?= $this->Form->checkbox('services[]', ['value' => 'Service 1', 'id' => 'service1', 'hiddenField' => false]); ?>
<?= $this->Form->checkbox('services[]', ['value' => 'Service 2', 'id' => 'service2', 'hiddenField' => false]); ?>
<?= $this->Form->checkbox('services[]', ['value' => 'Service 3', 'id' => 'service3', 'hiddenField' => false]); ?>

当我提交表单并调试输出时:

// in my Controller
if ($this->request->is('post')) {
    debug($this->request->getData());
}

我得到:

'services' => [
    (int) 0 => 'Service 1',
    (int) 1 => 'Service 3',
],

这很好,因为它有选定的服务,就用户在表单的这一部分提交的数据而言,这是我所需要的。

但是当提交表单后提交错误时:

Notice (8): Array to string conversion [CORE/src/View/Widget/CheckboxWidget.php, line 93]

None 的复选框被选中(而表单上的其余字段填充了请求数据,尽管它们都是文本输入而不是复选框)。看起来像这样:

为什么会这样?正在生成的标记使用复选框名称的数组语法(例如 services[]),据我所见,它是完全有效的 HTML 并且在链接 post 上使用的东西没有有人说这是个问题。

这是 CakePHP 的特定问题(例如,Form Helper 某处使用了错误的语法)还是 HTML 或 PHP 的解释方式的一般问题?

我记得我曾经为我的项目写过一个帮助程序 类似于

namespace App\View\Helper;

use Cake\View\Helper\FormHelper;

/**
 * Allows forms with fieldname[] syntax.
 *
 * @author Mark Scherer
 * @license MIT
 * @property \Cake\View\Helper\UrlHelper $Url
 * @property \App\View\Helper\HtmlHelper $Html
 */
class ArrayFormHelper extends FormHelper
{
    /**
     * @var int
     */
    protected $counter = 0;

    /**
     * @var array
     */
    protected $data = [];

    /**
     * @param array $config
     *
     * @return void
     */
    public function initialize(array $config): void
    {
        $this->data = $this->getView()->getRequest()->getData();
    }

    /**
     * @return void
     */
    public function endRow(): void
    {
        $this->counter++;
    }

    /**
     * @return void
     */
    public function reset(): void
    {
        $this->counter = 0;
    }

    /**
     * @param string $field
     * @param array $options
     *
     * @return string
     */
    public function arrayControl(string $field, array $options = []): string
    {
        if (array_key_exists($this->counter, $this->data[$field])) {
            $options['default'] = $this->data[$field][$this->counter];
            $this->getView()->setRequest($this->getView()->getRequest()->withoutData($field));
        }

        return $this->control($field . '[]', $options);
    }
}

用作示例

echo $this->ArrayForm->arrayControl('module', ['label' => 'Module', 'placeholder' => 'CamelCase']);
echo $this->ArrayForm->arrayControl('type', ['label' => 'Type', 'options' => ['patch' => 'patch', 'minor' => 'minor', 'major' => 'major'], 'empty' => true]);
$this->ArrayForm->endRow();

如果这不在循环内(就像我的情况一样),则不需要 counter 和 endRow 的东西。

您的字段名称与数据名称相同,例如 services,因此表单助手将为每个单独控件的当前值选取一个数组,这将失败,因为“ 应该检查”逻辑需要比较两个平面值。

如果你想像这样创建单独的复选框,那么你要么需要注意为单独的控件传递可能的 POST 数据,这就是 mark 的例子所做的,或者你需要测试手动输入数据并标记相应的复选框,这是一个示例:

$values = (array)$this->Form->getSourceValue('services');

echo $this->Form->checkbox('services[]', [
    'value' => 'first',
    'checked' => in_array('first', $values),
    // ...
]);
echo $this->Form->checkbox('services[]', [
    'value' => 'second',
    'checked' => in_array('second', $values),
    'hiddenField' => false,
    // ...
]);
echo $this->Form->checkbox('services[]', [
    'value' => 'third',
    'checked' => in_array('third', $values),
    'hiddenField' => false,
    // ...
]);

话虽这么说,对于您的特定情况,您应该能够简单地使用多复选框控件,它将处理查找数据并自动标记复选框:

echo $this->Form->select(
    'services',
    $options,
    ['multiple' => 'checkbox', /* ... */]
);

如果您想使用名称作为选项值,$options 需要是一个数组,例如:

[
    'Service 1' => 'Service 1',
    'Service 2' => 'Service 2',
    // ...
]

因为数组索引用于复选框值,而数组值用于复选框标签。

另见