CakePhp 3.5:在 returns false 的 beforeDelete() 中保存其他数据

CakePhp 3.5: save other data in beforeDelete() which returns false

我正在实施 ReviewableBehavior 以实施四眼原则。该行为实现 beforeDelete()beforeSave()afterSave() 并使用 reviews table 来存储 CUD 请求。

  1. 对于添加的记录,创建一条$review记录并保存在afterSave()中(因为只有我们有新添加记录的id,我们需要将其存储在$review)
  2. 对于已编辑的记录,在beforeSave()中,已更改的值保存在$review记录中,在已编辑的记录中,这些字段值被设置回其原始值(所以基本上没有更改已保存)
  3. 对于删除的记录,在beforeDelete()保存了一个$review存放删除请求,false是return为了取消删除

数字 3. 是挑战,因为尽管 $review 始终具有正确设置的主键值,就好像保存实际上是成功的,并且 save($review) returned true 就好像一切顺利,实际上并没有存入数据库。

据我了解,原因是:默认情况下,删除是在事务中完成的。事务在table的delete()开始,然后beforeDelete()的行为被触发。在事件处理程序中,我调用 ReviewTable->save($review)。由于事务已启动,此 save() 发生在事务内。然后我return false,因为我要停止删除。这将回滚事务并随之回滚 ReviewTable->save($review).

解决方案尝试:

目前我采用最后一种方法,但我真的很想听听对此的一些意见,以及是否有更好的方法以某种方式保持交易,但节省一些东西"in between"。

使用单独的方法是一种明智的方法。另一种选择可能是通过停止 Model.beforeDelete 事件来规避删除过程,这样做时您可以 return true 表示删除操作成功,即不会发生回滚。

需要注意的是,停止事件可能会导致队列中的其他监听器得不到通知!此外,停止常规删除过程将防止级联删除(即删除关联记录)和 Model.afterDelete 事件,因此如果您需要级联删除,则需要手动触发它们,并且 afterDelete在任何情况下,通常都应为成功删除触发事件。

这是一个简单粗暴的示例,另请参阅 \Cake\ORM\Table::_processDelete() 了解常规删除过程的工作原理:

public function beforeDelete(
    \Cake\Event\Event $event,
    \Cake\Datasource\EntityInterface $entity,
    \ArrayObject $options
) {
    // this will prevent the regular deletion process
    $event->stopPropagation();

    $table = $event->getSubject();

    // this deletes associated records
    $table->associations()->cascadeDelete(
        $entity,
        ['_primary' => false] + $options->getArrayCopy()
    );

    $result = /* create review record */;
    if (!$result) {
        // this will cause a rollback
        return false;
    }

    $table->dispatchEvent('Model.afterDelete', [
        'entity' => $entity,
        'options' => $options,
    ]);

    return true;
}

另见