【问题标题】:Saving data to the join table using control options in CakePHP 3.x使用 CakePHP 3.x 中的控制选项将数据保存到连接表
【发布时间】:2017-08-29 10:04:44
【问题描述】:

我了解了here 如何在 CakePHP 3.x 中添加或编辑 student 时将数据保存到连接表 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. 需要从列表中选择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,显示前 3rd 5th 的 grades和第 7 个courses 和表格迫使我检查这三个框。我知道第一条记录消失了,因为我的coursesid=1 开头(循环中的$key 也是如此)和'courses.0。 id' 因此丢失,但一般问题是beforeMarshal 函数删除的空字段在edit.ctp 表单中不再识别,我找不到编辑student's 记录的合理方法。

【问题讨论】:

    标签: mysql cakephp cakephp-3.0 jointable


    【解决方案1】:

    没有内置支持您要实现的目标,您必须提出自定义解决方案,这可能需要混合使用表单和编组逻辑或 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'));
        });
    });
    

    另见

    【讨论】:

    • 非常感谢您优雅的解决方案和详细的解释!我开始实现第一个并收到此错误消息:Cannot use object of type of Cake\ORM\Query as array (line 'value' => $courses[0]->id,)
    • 您必须先使用$courses->toArray() 将其转换为数组,而$courses 需要是常规查询(而不是列表查询)。我假设您希望根据您的示例 sn-p 生成特定数量的课程。或者,您可以遍历$courses,并使用键/值而不是访问属性,以防$courses 是列表查找器查询。
    • 太棒了!一切都按照您的解释进行。一如既往。非常感谢!
    • 我编辑了主要问题,以明确其中一种解决方案非常适用于 add 方法,但至少在我的实现中,不提供编辑方式。
    • 我正在实现 resetpassword 功能,而上面的 beforeMarshal 功能现在出现问题,因为当我尝试更新用户密码时它会激活。有什么办法可以逃脱吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多