我是CakePhp的新手,目前正在尝试实现一个简单的票务系统,包括工单,事件,任务,用户等。在基本的 CRUD 功能下,状态已通过 ajax 调用标记为完成的工单应生成一个新工单(表示工作流中的下一步)。
但是,在Ticket::afterSave()
中创建下一个票证作为通过 ajax 对$this->saveField()
的回调最终会失败,并出现完整性约束违规,而"正常烘焙"的edit()
调用有效。 蛋糕似乎只是忽略了生成的$this->save()
上的一些要保存的字段MySQL 插入语句,我想不出解释。
这里是门票的模型...
<? class Ticket extends AppModel {
// [...]
public function update($status) {
return $this->saveField('status', $status);
}
public function afterSave($created, $options = array()) {
//[...] if ticket state was changed to done:
// generate data for Ticket with next Task in Workflow
$this->Event->id = $this->field('event_id');
$ticketData = $this->Event->generateNext();
// check if data is correct
debug($ticketData);
// create new ticket
$this->create();
return $this->save($ticketData);
}
}
一个Ticket
belongs_to
User
,Task
和Event
完成的工单的事件Event->generateNext()
生成下一个工单的数据(在LinkableBehavior的帮助下,因为可包含似乎不支持深层条件)。数据是正确的,上面的调试总是打印如下:
array(
'Ticket' => array(
'event_id' => '11720',
'task_id' => '9',
'user_id' => '1',
'status' => 'Requested')
)
但是,当 ajax 调用update
函数时,创建失败并显示:
Error: [...] Integrity constraint violation: Cannot add or update a child row: a foreign key constraint fails (`table`.`tickets`, CONSTRAINT `fk_tickets_users1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) [...])
。显示 SQL 查询:
'INSERT INTO `table`.`tickets` (`status`, `modified`, `created`) VALUES ('Requested', '2014-02-05 22:00:32', '2014-02-05 22:00:32')'
如您所见,生成的查询完全错过了user_id
等的字段,这当然会导致创建失败。但是调试证明了它们的存在?!混乱。 但是,在烘焙edit
函数中调用Ticket::save()
时,查询结果很好:
'INSERT INTO `table`.`tickets` (`status`, `event_id`, `task_id`, `user_id`, `modified`, `created`) VALUES ('Requested', 11720, 9, 1, '2014-02-05 20:34:25', '2014-02-05 20:34:25')'
我想我可以通过使用自定义查询来避免这种行为,例如Ticket->query()
?但我宁愿了解不同的结果,并以"蛋糕方式"去做。 我希望这在某种程度上是可以理解的,并且非常感谢任何帮助。
提前非常感谢!
由于您在状态字段初始更新后从工单本身的 afterSave() 方法中创建新工单,因此模型的白名单设置为您最初保存的唯一字段(状态)。 所有其他字段均由以下人员丢弃
$this->save($ticketData);
将其更改为:
$this->save($ticketData, false, array(
'event_id',
'task_id',
'user_id',
'status'
);
注意对 afterSave() 的递归调用。上面的调用 $this->afterSave() 将在 Save() 本身之后再次调用。