我有一个插件,其中包含它使用的所有表。
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
我的问题是:
- 这是一个已经引入的蛋糕bug吗?
- 如果没有,我怎么能告诉它从我的插件表的关联?
我知道你们会问的第一件事是看到我的模型关联和一切,但这是在从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']
]);