CakePHP 3 - 保存时在关联中找不到插件 table

CakePHP 3 - Plugin table not found in associations when saving

我有一个插件,其中包含它使用的所有 tables。

plugins
  /MyPlugin
    /src
      /Model
        /Table
          EventsTable.php
          EventValuesTable.php
          ...

我正在尝试保存一个 Event 实体及其相关的 hasMany EventValues 关联。

$data = [
    'event_type_id' => 5,
    'event_values' => $values // An array of EventValue entities
];
$event = $eventsTable->newEntity($data, [
    'associated' => ['MyPlugin.EventValues']
]);

但是,它找不到关联的 table 并给出以下错误:

无法为 "MyPlugin" 关联整理数据。它与 "Events"

无关

现在我已经花了几个小时调试它,这是我目前的状态:

问题:

Marshaller class 似乎将 MyPlugin.EventValues 关联视为嵌套模型关联 - 即它认为 MyPlugin 是与正在保存的主要实体 (Event)。它不是在我的插件的 src/Table 目录中寻找模型。

我需要找到一种方法让 Cake 意识到 MyPlugin.EventValues 意味着:

plugins/MyPlugin/src/Model/Table/EventValuesTable.php

相反,它将其分析为:

src/Model/Table/MyPluginsTable.php

所以我的问题是:

  1. 这是引入的 Cake 错误吗?
  2. 如果不是,我如何告诉它从我的插件 tables 建立关联?

我知道你们首先要问的是查看我的模型关联和所有内容,但在从 Cake 3.1 更新到 3.3 之前这是有效的,我 100% 确定关联是正确的。请记住所有 table 都在插件 table 目录中,主应用程序 table 目录中没有任何内容。

关联别名无需插件

您似乎混淆了 class 名称和关联别名,后者可以独立于使用的 class 定义,并且可能的插件前缀正在从中丢弃。

例如创建关联时

$this->hasMany('MyPlugin.EventValues');

关联class会将整个别名(即MyPlugin.EventValues)设置为className选项,然后拆分class名称(EventValues)来自插件名称(MyPlugin),并将前者设置为关联名称(即EventValues)。

这与像

这样定义关联实际上是一样的
$this->hasMany('EventValues', [
    'className' => 'MyPlugin.EventValues'
]);

所以从逻辑上讲,您现在必须通过无插件名称来引用关联,即

'associated' => ['EventValues']

然后 ORM 将从关联的 className 选项值前缀的插件中计算出正确的 class名称。

不存在的关联现在会严重失败

你在那里做的事情在 3.1 中只是运气好,在 3.3 之前,不存在的关联是 discarded in the marshalling process,导致事情可能会悄无声息地失败,即 ['MyPlugin.EventValues'] 实际上与通过相同一个空数组。

从 3.3 开始,不存在的关联将 cause an exception to be raised,这就是您所看到的。引自文档:

Table::newEntity() and Table::patchEntity() will now raise an exception when an unknown association is in the associated key.

Cookbook > 3.X Migration Guide > 3.3 Migration Guide > ORM Improvements.

您不能编组实体

不支持编组实体。如果你想传递现成的实体,你不能将相应的关联标记为已编组,那样会出错,准确地说,你会留下一个空的 event_values 属性,如 non-array values are being discarded.

所以,正如已经提到的,它只是靠运气。在 3.1 中,你不存在的关联将被丢弃,导致 event_values 属性 被排除在关联编组过程之外,导致传递的数据按原样设置在 $event 实体上.

如果您已经为关联创建了现成的实体,请不要将其标记为已编组

$event = $eventsTable->newEntity($data);

或在编组过程后将它们设置在生成的实体上

$event = $eventsTable->newEntity($data);
$event->event_values = $arrayOfEventValueEntities;

当然,如果事先没有特定的原因需要创建实体,那么只需将数据以数组格式传递,然后让编组器将其相应地转换为实体

$data = [
    'event_type_id' => 5,
    'event_values' => [
        ['event_value_property' => 'value'],
        ['event_value_property' => 'value'],
        // ...
    ]
];
$event = $eventsTable->newEntity($data, [
    'associated' => ['EventValues']
]);