【问题标题】:How to create a self BelongsToMany relation in CakePHP 3如何在 CakePHP 3 中创建一个自我 BelongsToMany 关系
【发布时间】:2023-03-04 22:22:01
【问题描述】:

我有一个带有“projekte”表(项目的德语单词)的数据库。 一些项目相互关联。 所以我想有一个 BTM 关系。

我创建了一个包含以下字段的 joinTable“projektverbindungen”:

projekt_id
nebenprojekt_id

我在这里发现了一个类似的问题:BelongstoMany relationship between a table and itself 我尝试了 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。好像没什么区别。

然后我尝试使用 through-option,但结果更糟。 所以我继续尝试用上述方法找到解决方案。

第二次编辑

projekverbindungen 可以在 Projekt.php 中访问:

protected $_accessible = [
  'name' => true,
  'projekteigenschaft' => true,
  'projekte' => true,
  'projektverbindungen' => true,
];

requestData的调试:

[
  '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' => '\1e',
  '/^(projekteigenschaft|projektverbindung)$/i' => '\1en',
]);
Inflector::rules('singular', [
  '/^(projekt)e$/i' => '\1',
  '/^(projekteigenschaft|projektverbindung)en$/i' => '\1',
]);

根据您的建议,我在关联的定义中额外添加了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'
}

但“projektverbindungen”表中仍然没有新条目

【问题讨论】:

  • 您究竟是如何尝试在链接问题的答案中实施建议的?
  • @ndm 我编辑了我的问题并为您的问题添加了答案。
  • 你是否让projektverbindungen 可以在你的(大概)Projekt 实体类中访问?如果没有,试试看保存是否有效。如果它不起作用,请将debug() 与您的修补实体一起使用并显示它的外观。
  • 是的。我相应地更新了问题。
  • 我应该马上就看到了,根据惯例,belongsToMany 的关联属性名称是复数,但是变形器不会说德语,它基于英语语言规则,所以it will expect an s appended,即projektverbindungens。使用property 选项定义自定义属性名称,即projektverbindungen,添加custom inflection rule,或切换到全英文编码。

标签: cakephp database-design relationship cakephp-3.0


【解决方案1】:

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

尽管如此,也许其他人也会犯同样的错误,这个帖子可以提供帮助。

第二件事是不要使用joinable的名字作为协会的名字。

剩下的就简单了……

使关联在实体类 (Projekt.php) 中可访问:

protected $_accessible = [
  'name' => true,
  'projekteigenschaft' => true,
  'nebenprojekte' => true,
];

ProjekteController.php(“添加”和“编辑”):

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' => '\1e',
  '/^(projekteigenschaft)$/i' => '\1en',
]);
Inflector::rules('singular', [
  '/^(projekt|nebenprojekt)e$/i' => '\1',
  '/^(projekteigenschaft)en$/i' => '\1',
]);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多