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


CakePHP 3 - Plugin table not found in associations when saving

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

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']
]);

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

无法封送"MyPlugin"关联的数据。它与"Events"

没有关联。

现在我花了几个小时调试这个,这是我到目前为止的进展:

  • 这个异常是由3.3版引入Cake核心的一段新代码引发的

  • 从'Cake'ORM'Marshaller.php(第94行)抛出异常,当它试图分解associated数组时。

问题:

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

我需要找到一种方法让Cake意识到MyPlugin.EventValues的意思是:

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

相反,它分析它为:

src/Model/Table/MyPluginsTable.php

我的问题是:

  1. 这是一个已经引入的蛋糕bug吗?
  2. 如果没有,我怎么能告诉它从我的插件表的关联?

我知道你们会问的第一件事是看到我的模型关联和一切,但这是在从Cake 3.1更新到3.3之前工作的,我100%肯定这些关联是正确的。请记住,所有的表都在插件表目录中,没有任何东西来自主应用表目录。

关联别名是plugin-less

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

例如,当创建像

这样的关联时
$this->hasMany('MyPlugin.EventValues');

关联类将整个别名(即MyPlugin.EventValues)设置为className选项,然后将类名(EventValues)与插件名(MyPlugin)分开,并将前者设置为关联名(即EventValues)。

这实际上等同于定义像

这样的关联
$this->hasMany('EventValues', [
    'className' => 'MyPlugin.EventValues'
]);
所以从逻辑上讲,你现在必须通过无插件的名称来引用关联,即
'associated' => ['EventValues']

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

不存在的关联现在会失败

你在3.1中所做的只是运气,和3.3之前一样,不存在的关联在编组过程中被丢弃,导致事情可能无声地失败,即['MyPlugin.EventValues']实际上与传递空数组相同。

从3.3开始,不存在的关联将导致引发异常,这就是您所看到的。引用自文档:

Table::newEntity()Table::patchEntity()将在associated键中存在未知关联时引发异常。

Cookbook>X迁移指南> 3.3迁移指南> ORM改进.

不能编排实体

不支持编组实体。如果你想传递现成的实体,你不能将相应的关联标记为被编组,这会出错,确切地说,你会留下一个空的event_values属性,因为非数组值被丢弃

所以,正如已经提到的,它只能靠运气。在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']
]);