CakePHP 3 - 如何仍然包含()软删除的实体?

CakePHP 3 - How to still contain() soft-deleted entities?

我有一个 Orders 和一个 Users table,这样 Orders belongsTo Users.

我希望用户能够软删除他们的帐户,所以我添加了一个删除字段并修改了删除方法。出于管理目的需要用户信息,因此没有硬删除。

我还覆盖了 UsersTable 的默认查找器,这样删除的用户将不会在列表中弹出,也不会作为 Users->get():

的结果弹出
public function findAll(Query $query, array $options)
{
    return $query->where(['Users.deleted' => false]);
}

我对它的工作方式很满意,主要是我现在不能忘记排除已删除的用户,因为默认查找器已经完成了这项工作。

问题是当用户包含在订单中时,我仍然想包括该用户:

$order = $this->Orders->get($id, ['contain' => 'Users']);

并且显然在使用 contain() 时使用了 findAll(),因为这不包括已删除的用户。

我怎样才能在 contain() 中包含软删除的实体?

是否可以为包含设置不同的默认查找器?

例如,您可以使用 contain 的 finder 选项来指定要使用的查找器,例如:

$this->Orders->get($id, [
    'contain' => [
        'Users' => [
            'finder' => 'withDeleted'
        ]
    ]
]);

或直接修改查询:

$this->Orders->get($id, [
    'contain' => [
        'Users' => function (\Cake\ORM\Query $query) {
            return $query->find('withDeleted');
        }
    ]
]);

另见 Cookbook > Database Access & ORM > Query Builder > Passing Conditions to Contain

但是 任何 自定义查找器都会绕过您修改后的 all 查找器,这表明您的方法存在缺陷,一旦查询使用不同的查找器,并且不会也明确使用 all 查找器,您的条件将不会应用,您很可能不希望如此轻易地发生。

更好的方法可能是使用 Model.beforeFind event/callback。这是一个使用选项方法的基本的、相当严格的示例:

public function beforeFind(\Cake\Event\Event $event, \Cake\ORM\Query $query, \ArrayObject $options)
{
    if (!isset($options['findWithDeleted']) ||
        $options['findWithDeleted'] !== true
    ) {
        $query->where(['Users.deleted' => false]);
    }
}

public function findWithDeleted(\Cake\ORM\Query $query, array $options)
{
    return $query->applyOptions(['findWithDeleted' => true]);
}

这将确保仅当存在 findWithDeleted 选项并设置为 true 时,才不会应用该条件。

您可能还想看看可以处理此问题的插件,例如 https://github.com/usemuffin/trash.