如何在 CakePHP 3 中创建自己的 BelongsToMany 关系
How to create a self BelongsToMany relation in CakePHP 3
我有一个带有 table "projekte"(项目的德语单词)的数据库。
一些项目彼此相关。
所以我想有一个BTM关系。
我创建了一个包含以下字段的 joinTable "projektverbindungen":
projekt_id
nebenprojekt_id
我在这里发现了一个类似的问题: 我尝试了 ndm 的答案,但没有成功。
这是我的 ProjekteTable.php
class ProjekteTable extends Table {
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('projekte');
$this->setDisplayField('name');
$this->setPrimaryKey('id');
$this->hasOne('Projekteigenschaften', [
'foreignKey' => 'projekt_id',
'dependent' => true,
]);
$this->belongsToMany('Projekte', [
'foreignKey' => 'projekt_id',
'targetForeignKey' => 'nebenprojekt_id',
'joinTable' => 'projektverbindungen',
]);
}
}
这是我的模板 (add.ctp)
<?php
echo $this->Form->create($projekt);
echo $this->Form->control('name', ['class' => 'form-control']);
echo $this->Form->control('projekteigenschaft.projektverantwortlich');
echo $this->Form->control('projekteigenschaft.beschreibung');
echo $this->Form->control('projekte._ids', ['options' => $projekte, 'multiple' => true]);
echo $this->Form->button(__('Submit'));
echo $this->Form->end();
?>
第一步,将项目与相关项目一起保存,效果如预期。
已创建项目的 id
被保存为 projektverbindungen.projekt_id
并且相关项目的 id
被保存为 projektverbindungen.nebenprojekt_id
.
当我查询一个与其他项目无关的项目时:
$projekt = $this->Projekte->get($id, [
'contain' => ['Projekteigenschaften']
]);
查询如下所示:
SELECT Projekte.id AS `Projekte__id`, Projekte.name AS `Projekte__name`, Projekteigenschaften.id AS `Projekteigenschaften__id`, Projekteigenschaften.projektverantwortlich AS `Projekteigenschaften__projektverantwortlich`, Projekteigenschaften.beschreibung AS `Projekteigenschaften__beschreibung`, Projekteigenschaften.projekt_id AS `Projekteigenschaften__projekt_id` FROM projekte Projekte LEFT JOIN projekteigenschaften Projekteigenschaften ON Projekte.id = (Projekteigenschaften.projekt_id) WHERE (Projekte.id = :c0 AND (Projekte.deleted) IS NULL)
调试结果如下:
"id": "6862279f-8134-401f-86ff-9278a3bfa5c3",
"name": "My Project",
"projekteigenschaft": {
"id": "89d9e241-e700-4c31-9266-ee5717f2a0aa",
"projektverantwortlich": "Blisginnis, Ralf",
"beschreibung": ""
}
一切正常。
但是当我像这样添加要包含的项目时:
$projekt = $this->Projekte->get($id, [
'contain' => ['Projekteigenschaften', 'Projekte']
]);
查询看起来和上面一样,但实体看起来有点不同:
"Projekteigenschaften": {
"id": "89d9e241-e700-4c31-9266-ee5717f2a0aa",
"projektverantwortlich": "Blisginnis, Ralf",
"beschreibung": ""
}
Projekteigenschaften 似乎不再是 hasOne 关系,"Projekte" 被完全忽略。
有人知道我做错了什么吗?或者我应该更喜欢其他方式吗?
在 ndm 的评论后编辑
我试过这样定义关系:
$this->belongsToMany('Projektverbindungen', [
'class' => 'Projekte',
'foreignKey' => 'projekt_id',
'targetForeignKey' => 'nebenprojekt_id',
'joinTable' => 'projektverbindungen',
]);
并像这样更改了 add.ctp 模板:
echo $this->Form->control('projektverbindungen._ids', ['options' => $projekte, 'multiple' => true]);
但是它并没有保存关系。
我还尝试将 joinTable 重命名为 projekte_projekte。它似乎没有任何区别。
然后我尝试使用直通选项,但结果更糟。
于是我继续尝试用上面介绍的方法寻找解决方案。
第二次编辑
projekverbindungen ist 可在 Projekt.php:
中访问
protected $_accessible = [
'name' => true,
'projekteigenschaft' => true,
'projekte' => true,
'projektverbindungen' => true,
];
请求数据的调试:
[
'name' => 'My Project',
'projekteigenschaft' => [
'projektverantwortlich' => 'John Doe',
'beschreibung' => '',
'projektverbindungen' => [
'_ids' => [
(int) 0 => '809031f2-4ecd-4dfb-82d5-2c911286dd21'
]
]
]
补丁后实体调试:
object(App\Model\Entity\Projekt) {
'name' => 'My Project',
'projekteigenschaft' => object(App\Model\Entity\Projekteigenschaft) {
'projektverantwortlich' => 'John Doe',
'beschreibung' => '',
'[new]' => true,
'[accessible]' => [
'projektverantwortlich' => true,
'beschreibung' => true,
'projekt_id' => true,
'projekt' => true
],
'[dirty]' => [
'projektverantwortlich' => true,
'beschreibung' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Projekteigenschaften'
},
'projektverbindungen' => [],
'[new]' => true,
'[accessible]' => [
'name' => true,
'projekteigenschaft' => true,
'projekte' => true,
'projektverbindungen' => true
],
'[dirty]' => [
'name' => true,
'projekteigenschaft' => true,
'projektverbindungen' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Projekte'
}
第三次编辑
在我的 bootstrap.php 我有这个:
Inflector::rules('plural', [
'/^(projekt)$/i' => 'e',
'/^(projekteigenschaft|projektverbindung)$/i' => 'en',
]);
Inflector::rules('singular', [
'/^(projekt)e$/i' => '',
'/^(projekteigenschaft|projektverbindung)en$/i' => '',
]);
根据你的推荐,我在协会的定义中额外添加了propertyName
:
$this->belongsToMany('Projektverbindungen', [
'class' => 'Projekte',
'propertyName' => 'Projektverbindungen',
'foreignKey' => 'projekt_id',
'targetForeignKey' => 'nebenprojekt_id',
'joinTable' => 'projektverbindungen',
]);
之后,修补后的实体如下所示:
object(App\Model\Entity\Projekt) {
'name' => 'My Project',
'projekteigenschaft' => object(App\Model\Entity\Projekteigenschaft) {
'projektverantwortlich' => 'John Doe',
'beschreibung' => '',
'[new]' => true,
'[accessible]' => [
'projektverantwortlich' => true,
'beschreibung' => true,
'projekt_id' => true,
'projekt' => true
],
'[dirty]' => [
'projektverantwortlich' => true,
'beschreibung' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Projekteigenschaften'
},
'projektverbindungen' => [
'_ids' => [
(int) 0 => '1e28a3d1-c914-44be-b821-0e87d69cd95f'
]
],
'[new]' => true,
'[accessible]' => [
'name' => true,
'projekteigenschaft' => true,
'projekte' => true,
'projektverbindungen' => true
],
'[dirty]' => [
'name' => true,
'projekteigenschaft' => true,
'projektverbindungen' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Projekte'
}
但是 table "projektverbindungen"
中仍然没有新条目
ndm 的最后一个建议成功了。
现在它按预期工作。非常感谢!
这是正确的设置:
ProjekteTable.php
$this->belongsToMany('Nebenprojekte', [
'className' => 'Projekte',
'foreignKey' => 'projekt_id',
'targetForeignKey' => 'nebenprojekt_id',
'joinTable' => 'projektverbindungen',
]);
这里我用了属性 class
而不是className
,这是最大的问题。
这真是令人尴尬,因为在 Cookbook 中是 属性 的正确名称:
https://book.cakephp.org/3/en/orm/associations.html#belongstomany-associations
尽管如此,也许其他人也会犯同样的错误,这个帖子可以提供帮助。
第二件事是不要使用可联合的名字作为协会的名称。
剩下的就是直截了当...
使关联在实体中可访问 Class (Projekt.php):
protected $_accessible = [
'name' => true,
'projekteigenschaft' => true,
'nebenprojekte' => true,
];
ProjekteController.php("add" 和 "edit"):
public function add()
{
$projekt = $this->Projekte->newEntity();
if ($this->request->is('post')) {
$projekt = $this->Projekte->patchEntity($projekt, $this->request->getData());
if ($this->Projekte->save($projekt)) {
$this->Flash->success(__('flash message'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('error message'));
}
$projekte = $this->Projekte->find('list');
$this->set(compact('projekt', 'projekte'));
}
public function edit($id = null)
{
$projekt = $this->Projekte->get($id, [
'contain' => ['Projekteigenschaften', 'Nebenprojekte']
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$projekt = $this->Projekte->patchEntity($projekt, $this->request->getData());
if ($this->Projekte->save($projekt)) {
$this->Flash->success(__('flash message'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('error message'));
}
$projekte = $this->Projekte->find('list')->where(['id !=' => $id]);
$this->set(compact('projekt', 'projekte'));
}
在 add.ctp 或 edit.ctp 等模板中:
echo $this->Form->control('nebenprojekte._ids', ['options' => $projekte, 'multiple' => true]);
如果您使用英语以外的其他语言,请不要忘记设置正确的词形变化规则。
bootstrap.php:
Inflector::rules('plural', [
'/^(projekt|nebenprojekt)$/i' => 'e',
'/^(projekteigenschaft)$/i' => 'en',
]);
Inflector::rules('singular', [
'/^(projekt|nebenprojekt)e$/i' => '',
'/^(projekteigenschaft)en$/i' => '',
]);
我有一个带有 table "projekte"(项目的德语单词)的数据库。 一些项目彼此相关。 所以我想有一个BTM关系。
我创建了一个包含以下字段的 joinTable "projektverbindungen":
projekt_id
nebenprojekt_id
我在这里发现了一个类似的问题:
这是我的 ProjekteTable.php
class ProjekteTable extends Table {
public function initialize(array $config)
{
parent::initialize($config);
$this->setTable('projekte');
$this->setDisplayField('name');
$this->setPrimaryKey('id');
$this->hasOne('Projekteigenschaften', [
'foreignKey' => 'projekt_id',
'dependent' => true,
]);
$this->belongsToMany('Projekte', [
'foreignKey' => 'projekt_id',
'targetForeignKey' => 'nebenprojekt_id',
'joinTable' => 'projektverbindungen',
]);
}
}
这是我的模板 (add.ctp)
<?php
echo $this->Form->create($projekt);
echo $this->Form->control('name', ['class' => 'form-control']);
echo $this->Form->control('projekteigenschaft.projektverantwortlich');
echo $this->Form->control('projekteigenschaft.beschreibung');
echo $this->Form->control('projekte._ids', ['options' => $projekte, 'multiple' => true]);
echo $this->Form->button(__('Submit'));
echo $this->Form->end();
?>
第一步,将项目与相关项目一起保存,效果如预期。
已创建项目的 id
被保存为 projektverbindungen.projekt_id
并且相关项目的 id
被保存为 projektverbindungen.nebenprojekt_id
.
当我查询一个与其他项目无关的项目时:
$projekt = $this->Projekte->get($id, [
'contain' => ['Projekteigenschaften']
]);
查询如下所示:
SELECT Projekte.id AS `Projekte__id`, Projekte.name AS `Projekte__name`, Projekteigenschaften.id AS `Projekteigenschaften__id`, Projekteigenschaften.projektverantwortlich AS `Projekteigenschaften__projektverantwortlich`, Projekteigenschaften.beschreibung AS `Projekteigenschaften__beschreibung`, Projekteigenschaften.projekt_id AS `Projekteigenschaften__projekt_id` FROM projekte Projekte LEFT JOIN projekteigenschaften Projekteigenschaften ON Projekte.id = (Projekteigenschaften.projekt_id) WHERE (Projekte.id = :c0 AND (Projekte.deleted) IS NULL)
调试结果如下:
"id": "6862279f-8134-401f-86ff-9278a3bfa5c3",
"name": "My Project",
"projekteigenschaft": {
"id": "89d9e241-e700-4c31-9266-ee5717f2a0aa",
"projektverantwortlich": "Blisginnis, Ralf",
"beschreibung": ""
}
一切正常。
但是当我像这样添加要包含的项目时:
$projekt = $this->Projekte->get($id, [
'contain' => ['Projekteigenschaften', 'Projekte']
]);
查询看起来和上面一样,但实体看起来有点不同:
"Projekteigenschaften": {
"id": "89d9e241-e700-4c31-9266-ee5717f2a0aa",
"projektverantwortlich": "Blisginnis, Ralf",
"beschreibung": ""
}
Projekteigenschaften 似乎不再是 hasOne 关系,"Projekte" 被完全忽略。
有人知道我做错了什么吗?或者我应该更喜欢其他方式吗?
在 ndm 的评论后编辑
我试过这样定义关系:
$this->belongsToMany('Projektverbindungen', [
'class' => 'Projekte',
'foreignKey' => 'projekt_id',
'targetForeignKey' => 'nebenprojekt_id',
'joinTable' => 'projektverbindungen',
]);
并像这样更改了 add.ctp 模板:
echo $this->Form->control('projektverbindungen._ids', ['options' => $projekte, 'multiple' => true]);
但是它并没有保存关系。
我还尝试将 joinTable 重命名为 projekte_projekte。它似乎没有任何区别。
然后我尝试使用直通选项,但结果更糟。 于是我继续尝试用上面介绍的方法寻找解决方案。
第二次编辑
projekverbindungen ist 可在 Projekt.php:
中访问protected $_accessible = [
'name' => true,
'projekteigenschaft' => true,
'projekte' => true,
'projektverbindungen' => true,
];
请求数据的调试:
[
'name' => 'My Project',
'projekteigenschaft' => [
'projektverantwortlich' => 'John Doe',
'beschreibung' => '',
'projektverbindungen' => [
'_ids' => [
(int) 0 => '809031f2-4ecd-4dfb-82d5-2c911286dd21'
]
]
]
补丁后实体调试:
object(App\Model\Entity\Projekt) {
'name' => 'My Project',
'projekteigenschaft' => object(App\Model\Entity\Projekteigenschaft) {
'projektverantwortlich' => 'John Doe',
'beschreibung' => '',
'[new]' => true,
'[accessible]' => [
'projektverantwortlich' => true,
'beschreibung' => true,
'projekt_id' => true,
'projekt' => true
],
'[dirty]' => [
'projektverantwortlich' => true,
'beschreibung' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Projekteigenschaften'
},
'projektverbindungen' => [],
'[new]' => true,
'[accessible]' => [
'name' => true,
'projekteigenschaft' => true,
'projekte' => true,
'projektverbindungen' => true
],
'[dirty]' => [
'name' => true,
'projekteigenschaft' => true,
'projektverbindungen' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Projekte'
}
第三次编辑
在我的 bootstrap.php 我有这个:
Inflector::rules('plural', [
'/^(projekt)$/i' => 'e',
'/^(projekteigenschaft|projektverbindung)$/i' => 'en',
]);
Inflector::rules('singular', [
'/^(projekt)e$/i' => '',
'/^(projekteigenschaft|projektverbindung)en$/i' => '',
]);
根据你的推荐,我在协会的定义中额外添加了propertyName
:
$this->belongsToMany('Projektverbindungen', [
'class' => 'Projekte',
'propertyName' => 'Projektverbindungen',
'foreignKey' => 'projekt_id',
'targetForeignKey' => 'nebenprojekt_id',
'joinTable' => 'projektverbindungen',
]);
之后,修补后的实体如下所示:
object(App\Model\Entity\Projekt) {
'name' => 'My Project',
'projekteigenschaft' => object(App\Model\Entity\Projekteigenschaft) {
'projektverantwortlich' => 'John Doe',
'beschreibung' => '',
'[new]' => true,
'[accessible]' => [
'projektverantwortlich' => true,
'beschreibung' => true,
'projekt_id' => true,
'projekt' => true
],
'[dirty]' => [
'projektverantwortlich' => true,
'beschreibung' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Projekteigenschaften'
},
'projektverbindungen' => [
'_ids' => [
(int) 0 => '1e28a3d1-c914-44be-b821-0e87d69cd95f'
]
],
'[new]' => true,
'[accessible]' => [
'name' => true,
'projekteigenschaft' => true,
'projekte' => true,
'projektverbindungen' => true
],
'[dirty]' => [
'name' => true,
'projekteigenschaft' => true,
'projektverbindungen' => true
],
'[original]' => [],
'[virtual]' => [],
'[hasErrors]' => false,
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Projekte'
}
但是 table "projektverbindungen"
中仍然没有新条目ndm 的最后一个建议成功了。 现在它按预期工作。非常感谢!
这是正确的设置:
ProjekteTable.php
$this->belongsToMany('Nebenprojekte', [
'className' => 'Projekte',
'foreignKey' => 'projekt_id',
'targetForeignKey' => 'nebenprojekt_id',
'joinTable' => 'projektverbindungen',
]);
这里我用了属性 class
而不是className
,这是最大的问题。
这真是令人尴尬,因为在 Cookbook 中是 属性 的正确名称:
https://book.cakephp.org/3/en/orm/associations.html#belongstomany-associations
尽管如此,也许其他人也会犯同样的错误,这个帖子可以提供帮助。
第二件事是不要使用可联合的名字作为协会的名称。
剩下的就是直截了当...
使关联在实体中可访问 Class (Projekt.php):
protected $_accessible = [
'name' => true,
'projekteigenschaft' => true,
'nebenprojekte' => true,
];
ProjekteController.php("add" 和 "edit"):
public function add()
{
$projekt = $this->Projekte->newEntity();
if ($this->request->is('post')) {
$projekt = $this->Projekte->patchEntity($projekt, $this->request->getData());
if ($this->Projekte->save($projekt)) {
$this->Flash->success(__('flash message'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('error message'));
}
$projekte = $this->Projekte->find('list');
$this->set(compact('projekt', 'projekte'));
}
public function edit($id = null)
{
$projekt = $this->Projekte->get($id, [
'contain' => ['Projekteigenschaften', 'Nebenprojekte']
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$projekt = $this->Projekte->patchEntity($projekt, $this->request->getData());
if ($this->Projekte->save($projekt)) {
$this->Flash->success(__('flash message'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('error message'));
}
$projekte = $this->Projekte->find('list')->where(['id !=' => $id]);
$this->set(compact('projekt', 'projekte'));
}
在 add.ctp 或 edit.ctp 等模板中:
echo $this->Form->control('nebenprojekte._ids', ['options' => $projekte, 'multiple' => true]);
如果您使用英语以外的其他语言,请不要忘记设置正确的词形变化规则。 bootstrap.php:
Inflector::rules('plural', [
'/^(projekt|nebenprojekt)$/i' => 'e',
'/^(projekteigenschaft)$/i' => 'en',
]);
Inflector::rules('singular', [
'/^(projekt|nebenprojekt)e$/i' => '',
'/^(projekteigenschaft)en$/i' => '',
]);