在单一简单格式中保存 HABTM 数据

使用 CakePHP 保存来自 HasAndBelongsToMany (HABTM) 关系的数据并非使用此框架最简单的部分。主要的困难在于 HABTM 数据的格式并不相同,无论您是想将现有记录关联在一起(仅更新联接表中的条目),还是创建新记录并将其关联(在模型表和联接表中创建新记录)。

当您脱离 CakePHP 标准和自动生成的视图,开始保存自定义数据(例如使用 JavaScript)时,您必须手动构建发送到控制器的数据,并且您完全控制其格式。因此,您可能希望确保您的记录和关联无论您是否创建新记录,都能以正确的方式保存。最简单的方法是确定一种格式,并始终以相同的方式构建数据,让模型处理数据(毕竟这是它们的工作)。

find() 返回的数据格式是最简单的使用方式:您可以在视图中轻松访问它,并且使用与 find() 和 save() 相同的数据格式是相当合理的。您拥有 find() 主模型的索引,以及每个关联模型的索引。hasMany 或 hasAndBelongsToMany 等多个关联模型对每个关联条目具有后续子数组。使用现有数据(我们有 ID)或新数据(还没有 ID)构建这种类型的数组非常简单。在下面的示例中,Foo hasAndBelongsToMany Bar

 `
array(
'Foo'=>array(
'id'=>'...',
...
),
'Bar'=>array(
(int)0=>array(
'id'=>'...',//ExistingBar,wehaveitsid
'name'=>'...'//Thenamemayhavebeenmodified
),
(int)1=>array(
'name'=>'...'//ThisBarwillbecreated
)
)
)
`

然后,使用一小段代码,您可以覆盖 saveAssociated() 函数来保存 Bar 的每个实例:创建新的实例(那些没有 ID 的)并更新现有的实例。然后,使用格式良好的关联数组(来自我们第一个案例的数组)调用库中的父 saveAssociated() 函数(您很少希望完全覆盖库中的函数)来更新联接表中的条目。将以下代码复制到您的 AppModel.php 中,技巧就完成了!

 `
publicfunctionsaveAssociated($data=null,$options=array()){
foreach($dataas$alias=>$modelData){
if(!empty($this->hasAndBelongsToMany[$alias])){
$habtm=array();
$Model=ClassRegistry::init($this->hasAndBelongsToMany[$alias]['className']);
foreach($modelDataas$modelDatum){
if(empty($modelDatum['id'])){
$Model->create();
}
$Model->save($modelDatum);
$habtm[]=empty($modelDatum['id'])?$Model->getInsertID():$modelDatum['id'];
}
$data[$alias]=array($alias=>$habtm);
}
}
returnparent::saveAssociated($data,$options);
}
`

阅读更多….