使用 CakePHP 3.x 中的控制选项将数据保存到连接 table

Saving data to the join table using control options in CakePHP 3.x

我学会了 如何在 CakePHP 3.x 中添加或编辑 student 时将数据保存到连接 table CoursesMemberships 的字段.为了为许多 courses 添加 grades 我可以在我的 addedit 表格中这样做:

echo $this->Form->control('courses.0.id', ['type' => 'select', 'options' => $courses]);
echo $this->Form->control('courses.0._joinData.grade');

echo $this->Form->control('courses.1.id', ['type' => 'select', 'options' => $courses]);
echo $this->Form->control('courses.1._joinData.grade');

echo $this->Form->control('courses.2.id', ['type' => 'select', 'options' => $courses]);
echo $this->Form->control('courses.2._joinData.grade');
...

但是这个表格:

  1. 每个student有固定数量的courses
  2. 需要 select 列表中的 course id ('type' => 'select');
  3. 将所有课程添加到学生记录中,即使没有参加(好吧,相应的 grade 字段可以保留为空,但仍然如此)。

有没有一种更简单的表格,其中列出了所有 courses,并且只能选中 course 出席并输入相应的 grade?我发现使用 control...

非常具有挑战性

编辑: @ndm 在下面提出了一个非常好的方法后,我在 add.ctp:

中实现了它
foreach ($courses as $key => $course) {

echo $this->Form->control('courses.'.$key.'.id', ['type' => 'checkbox', 'hiddenField' => false, 'value' => $key,
    'label' => $key]);
echo $this->Form->control('courses.'.$key.'._joinData.grades');
}

并相应地更正了 StudentsTable.php。它运行没有问题。

但是,如果我在 edit.ctp 中执行相同的操作,之前保存的记录(例如 1、3、5 和 7 courses 现在列为 1、2 和 3,显示 grades 表示前 3、5 和 7 courses,表格强制我选中这三个框。我知道第一条记录消失了,因为我的 coursesid=1 开头(等等$key 在循环中)并且因此缺少 'courses.0.id',但一般问题是 beforeMarshal 函数删除的空字段不再以 edit.ctp 形式识别,我找不到编辑 student's 记录的合理方法。

没有构建支持您要实现的目标,您必须想出一个自定义解决方案,这可能需要混合形式和编组逻辑,或者 JavaScript .

例如,您可以创建一个复选框列表,并使用 id 值(如果复选框未选中,则为零,如果 选中,则为 ID 选中)以在编组之前从提交的数据中删除未经选中的条目,如下所示:

echo $this->Form->control('courses.0.id', [
    'type' => 'checkbox',
    'value' => $courses[0]->id,
    'label' => $courses[0]->title
]);
echo $this->Form->control('courses.0._joinData.grade');

echo $this->Form->control('courses.1.id', [
    'type' => 'checkbox',
    'value' => $courses[1]->id,
    'label' => $courses[1]->title
]);
echo $this->Form->control('courses.1._joinData.grade');

// ...
// in the `StudentsTable` class

public function beforeMarshal(\Cake\Event\Event $event, \ArrayObject $data, \ArrayObject $options)
{
    forach ($data['courses'] as $key => $course) {
        if (empty($course['id'])) {
            unset($data['courses'][$key])
        }
    }
}

或者,您可以使用 JavaScript 禁用与复选框相关的控件,这样它们就不会被提交。为了使其正常工作,您需要确保禁用默认情况下为复选框生成的隐藏字段(请参阅 hiddenField 选项),否则将为未选中的复选框发送零。

这是一个快速的、未经测试的 jQuery 示例来说明原理:

echo $this->Form->control('courses.0.id', [
    'class' => 'course-checkbox',
    'data-join-data-input' => '#course-join-data-0',
    'type' => 'checkbox',
    'hiddenField' => false, // no fallback, unchecked boxes aren't being submitted
    'value' => $courses[0]->id,
    'label' => $courses[0]->title
]);
echo $this->Form->control('courses.0._joinData.grade', [
    'id' => 'course-join-data-0',
    'disabled' => true
]);

// ...
$('.course-checkbox').each(function () {
    var $checkbox = $(this);
    var $joinDataInput = $($checkbox.data('join-data-input'));

    $checkbox.on('change', function () {
        $joinDataInput.prop('disabled', !$checkbox.prop('checked'));
    });
});

另见