2017-08-29 63 views
1

我学会了here在CakePHP 3.x中添加或编辑student时,如何将数据保存到连接表CoursesMemberships的字段。为了增加grades许多courses我可以在我的addedit形式做到这一点:使用CakePHP 3.x中的控制选项将数据保存到连接表

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显示grades为前3日第5和第7 courses和我知道第一个记录消失了,因为我的coursesid=1(循环中的$键也是这样)开头,因此'courses.0.id'缺失,但一般问题是通过beforeMarshal函数删除空字段edit.ctp形式不再是公认的,我无法找到一个合理的方式来编辑student's记录。

回答

0

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

又见

+0

我非常感谢你的优雅的解决方案和详细的解释!我开始实现第一个并得到这个错误消息:不能使用Cake \ ORM \ Query类型的对象作为数组(行'value'=> $ courses [0] - > id) –

+0

您必须将其转换首先使用'$ courses-> toArray()'来创建一个数组,而'$ courses'需要是一个常规查询(而不是一个列表)。我假设你想给你的示例代码片段生成特定数量的课程。或者,您可以遍历'$ courses',并且在'$ courses'是列表查找器查询的情况下使用键/值而不是访问属性。 – ndm

+0

令人惊叹!一切正如你所解释的那样。一如既往。非常感谢! –

相关问题