当我通过带有belongsToMany-> link()函数的联结表链接所属的实体时,联结表上的afterSaveCommit事件不会触发。 link()函数似乎总是在事务中调用save(),并且我无法找到它调用afterSaveCommit的位置,因为没有来自实体的顶级save()调用。
这是疏忽还是设计?
答案 0 :(得分:0)
在多次单步执行代码并详细介绍之后,我认为“应该”的问题在双方都存在争议。
我发布我的解决方案,希望它能帮助别人。
我在ElasticSearch存储库中保留了非规范化的逻辑记录副本以进行分析,目标是在任何参与的关系实体更改时自动同步ES。所有相关实体都连接了afterSave触发器以同步ES。核心逻辑记录与静态数据列表有很多belongsToMany关系,因此有很多连接表和对link()的调用。 ES记录在每个记录之后都在更新,这需要花费过多的时间。
我使用了始终触发的afterSave事件,然后使用以下代码创建放置在所有相关表上的行为,这取决于在保存顶层实体时将选项_primary设置为true的行为。实际上,这是Cake用来确定何时触发afterSaveCommit事件的线索之一。
我确实担心使用未记录的下划线前缀标志,即使它在选项数组中传回。
class ElasticSyncBehavior extends Behavior
{
private static $_suspend_flag = false;
public function suspend_elastic_sync() {
self::$_suspend_flag = true;
}
public function resume_elastic_sync() {
self::$_suspend_flag = false;
}
public function afterSave($event, $entity, $options) {
if($options["_primary"]!=true || self::$_suspend_flag==true) {
return $entity;
}
// do synchronization here
return $entity;
}
public function afterDelete(Event $event, EntityInterface $entity, ArrayObject $options) {
if($options["_primary"]!=true || self::$_suspend_flag==true) {
return $entity;
}
// do synchronization here
return $entity;
}
}
这会强制执行相同的行为,其中同步仅在保存顶层实体后完成,在link()情况下是连接表。
我还在那里添加了删除事件,以处理unlink()调用以及级联删除。
如果那是你想要的,我还会提出一个完全覆盖行为的安全措施。使其成为行为的静态变量允许它在具有该行为的所有实体之间共享,即使它们每个都有自己的事件管理器。