CakePHP 保存 HABTM 数据
Posted
技术标签:
【中文标题】CakePHP 保存 HABTM 数据【英文标题】:CakePHP saving HABTM data 【发布时间】:2013-09-24 11:05:07 【问题描述】:我有 2 个模型,Client
和 Security
。它们与 HATBTM 关系相关联。
我制作了一个名为clients_securities
的连接表。所以Client
可以有很多证券,Security
可以属于很多Client
s。
这是我的关系定义:
//Client Model:
public $hasAndBelongsToMany = array(
'Security' =>
array(
'className' => 'Security',
'joinTable' => 'clients_securities',
'foreignKey' => 'client_id',
'associationForeignKey' => 'security_id',
'unique' => true,
)
);
//Security Model:
public $hasAndBelongsToMany = array(
'Client' =>
array(
'className' => 'Client',
'joinTable' => 'clients_securities',
'foreignKey' => 'security_id',
'associationForeignKey' => 'client_id',
'unique' => true,
)
);
然后我在客户端控制器中进行了编辑操作并执行了此操作:
public function edit($id = null)
if (!$id)
throw new NotFoundException(__('Invalid client'));
$client = $this->Client->findById($id);
if (!$client)
throw new NotFoundException(__('Invalid client'));
if ($this->request->is('post') || $this->request->is('put'))
$this->Client->id = $id;
if ($this->Client->saveAll($this->request->data))
$this->Session->setFlash(__('Client has been updated.'));
return $this->redirect(array('action' => 'edit', $id));
$this->Session->setFlash(__('Unable to update client.'));
if (!$this->request->data)
$this->request->data = $client;
$this->set('securities', $this->Client->Security->find('list'));
在我的编辑视图中,我使用 htmlHelper 构建表单,添加客户端表字段并生成多选:
echo $this->Form->create('Client'); //start the form for the client model
echo $this->Form->input('Security'); //generates a multi-select popuplated with securities
此外,我还以相同的形式为Client
提供了正常的直接形式输入。例如
echo $this->Form->input('name'); //Input for the client name
echo $this->Form->input('currency'); //Input for the client currency
...
在呈现表单时,所有这些输入都会生成并填充正确的值,但只保存直接客户端数据,而不是来自多选的 HABTM 数据。
当我提交表单时,clients_securities
表没有填充连接 ID。
我需要做些什么才能正确保存它,然后在我重新加载“编辑”视图时预先选择保存的证券。
编辑:为了澄清事情,这里是$this->request->data
的pr()
。
(值(“ALLCMCT LX Equity”)是securities
表的正确外键):
Array
(
[Client] => Array
(
[id] => 1212
[name] => Example Client
[currency] => GBP
[partner] =>
[risk_category_id] => 4
[client_code_id] => 1
[min_cash_balance] => 0
[active] => 1
[model] => 0
[institutional] => 0
[non_uk_situs] => 0
[reporting_status] => 0
)
[Security] => Array
(
[Security] => Array
(
[0] => .1muslib3 index
[1] => .eurib3 index
[2] => .ukcpi2 index
)
)
)
所以基本上,假设我的客户 ID 是 12345,Cake 应该像这样在 clients_securities
表中插入 2 条记录:
id | client_id | security_id
----------------------------
1 | 12345 | ALLCMCT LX Equity
2 | 12345 | APMKNTD LX Equity
如果我手动将一些连接记录添加到clients_securities
,当我去编辑客户时,多选中的证券会正确地预先选择,表明正在从连接表中读取数据。当我保存表单时,它实际上会删除连接记录,但不会保存新记录。
附加说明:我的安全 ID 存储为 CHAR(36)(如果有任何影响)。这不是一个自动递增字段,它包含证券的代码并且每个都是唯一的。
【问题讨论】:
看到这个***.com/a/18891807/1239506 我已经阅读了所有我能找到但没有成功的相关问题。 它应该按照您的方式工作。无论如何,您是否尝试过'unique' => 'keepExisting'
?另外,我认为 ID 格式不是问题,但只是为了确定您是否尝试过使用 INT 假 ID?最后:能否请您发布完整的pr($this->request->data)
(当然没有敏感数据)
修改问题以包含整个$this-request->data
。我想我想让unique
保持真实,因为我希望在插入新链接之前删除旧链接。
我的一个项目中也有类似的情况,但我有数字 ID。我尝试将 id 更改为 char(30) 并停止工作。如果我混合使用数字和字符值,它只会保存数字!
【参考方案1】:
问题在于security_id
和Security.id
的格式:不支持char。
我找到了这个ticket(但我在文档中没有找到任何参考资料)
您必须创建另一个带有数字 id
的列才能在 HABTM 关联中使用
【讨论】:
如果我将列类型更改为 CHAR(36) 会解决问题吗?编辑:不,它没有。 如果我将我的关系改造成hasMany
和belongsTo
关系,它会起作用吗?我该怎么做?
在我看来,最好的方法是使用数字 id 并将当前 id 重命名为“name”或“alfanumeric_identifier”。如果你不能这样做,那么你可以手动保存clients_securities
表中的项目,将$this->request->data['Security']['Security']
数组放在foreach cicle 中。即$this->Client->ClientsSecurity->save(array('client_id' => $client_id, 'security_id' => $security_id));
。请记住先删除旧关系
已解决!最后。你是绝对正确的。向我的证券表添加一个整数主键列现在可以正常工作。非常感谢,有赏金【参考方案2】:
像这样修改表单输入:
echo $this->Form->input('Security.Security');
【讨论】:
抱歉,这不会改变任何事情【参考方案3】:<?php
Model::saveAssociated(array $data = null, array $options = array());
or
Model::saveAll(array $data = null, array $options = array());
?>
欲了解更多信息,请访问:http://book.cakephp.org/2.0/en/models/saving-your-data.html
【讨论】:
如果上面的代码有任何问题,请告诉我。很高兴帮助你:) 我尝试将save
更改为saveAll
,但没有成功。多选中的数据看起来不像是与其他数据一起发布的。
如果我手动将连接记录添加到数据库,它会正确填充和预选证券。它只是不会保存。
事实上,当我保存它时,实际上删除了当前的连接记录而不保存新的。【参考方案4】:
我试试看……
你忘记了 $this->Client->read();在 $this->Client->id = $id 之后;在 edit() 函数中($this->Client 的内部未初始化,因此保存完成时不存在 client_id)。调用“findById”将只返回一个数组,但不会将数据读取到对象 $this->Client。
只是一个有根据的猜测..
【讨论】:
对不起,这个没有改变。【参考方案5】:也许我已经老了,但我猜你忘记在你的视图中创建一个带有客户端 ID 的隐藏输入
echo $this->Form->hidden('Client.id');
【讨论】:
该表单已经与Client
关联,并且其中有一个客户端ID 的输入。完整的请求数据现在有问题【参考方案6】:
它没有填充中介表,因为在填充了两个模型之后,它没有填充中介表的 ID。因此,用户 beforeSave 和 afterSave 函数将填充您的中介表。在 Client 模型中添加 beforesave 功能
public function beforeSave($options = array())
parent::beforeSave($options = array());
foreach (array_keys($this->hasAndBelongsToMany) as $model):
if(isset($this->data[$this->alias][$model])):
$this->data[$model][$model] = $this->data[$this->alias][$model];
unset($this->data[$this->alias][$model]);
endif;
endforeach;
return true;
在安全用户AfterSave功能中,
public $securityIdArray = array();
public function afterSave($created)
if($created)
$this->securityIdArray[] = $this->getInsertID();
return true;
首先保存安全并使用 $securityIdArray 获取 $this->Model->保存在控制器中的安全 ID。
$this->Security->securityIdArray[] = $void['Security']['id'];
嗯,正如@Arilia 所说,修改你的论坛输入字段
echo $this->Form->input('Security.Security');
并且不要为两个模型制作单独的表格
【讨论】:
最后一点,Security.Security
字段属于哪个表单模型?目的是为客户分配一种或多种证券,这类似于为帖子分配标签。客户表格肯定是正确的。
另外,Securities
模型永远不会,也不需要填充,只有连接表。表中已经有证券。目的是选择一些并让它们“属于”客户。以上是关于CakePHP 保存 HABTM 数据的主要内容,如果未能解决你的问题,请参考以下文章
cakephp 在不使用视图的情况下保存 HABTM 关系的数据
CakePHP 使用 saveAll:如何使用 HABTM 链接记录保存额外数据?