在不破坏 CakePHP 中的 buildRules() table 回调的情况下限制 beforeFind() table 回调的查询结果

Restrict query results on beforeFind() table call back without breaking buildRules() table callback in CakePHP

我目前 运行 我维护的旧 Cake 库存应用程序上的一些遗留代码存在问题。该应用程序包含库存项目,这些项目只能由与该项目位于同一位置的用户看到。出于这个原因,我们有这些项目以及许多其他模型来扩展 BaseTable。这实质上是获取登录用户能够使用 getUserLocationIds() 查看库存项目的位置的 ID,然后将输出附加到 beforeFindRule() 上的查询以分类用户不应该看到的项目:

<?php

class BaseTable extends Cake\ORM\Table
{
    public function beforeFind(Event $event, Query $query, ArrayObject $options)
    {
        parent::beforeFind($event, $query, $options);

        $repositoryTable = $query->getRepository()->getAlias();

        $loacationIds = Cake\ORM\TableRegistry::getTableLocator()
            ->get("Locations")
            ->getUserLocationIds();

        $query->andWhere([$repositoryTable . ".location_id IN " => $locationIds]);
        
    }
}

以上代码多年来一直在生产环境中运行良好。虽然现在我们得到的用户无法在他们的位置看到现有项目,因为软件已将其分配到他们无权访问的另一个位置。他们假设该项目不在系统中,并使用相同的 id_number 和 client_id.

创建另一个项目

ItemsTable 应该使用下面列出的 buildRule() 来限制这一点:

<?php

class ItemsTable extends BaseTable
{
    public function buildRules(Cake\ORM\RulesChecker $rules): Cake\ORM\RulesChecker
    {
        $rules->add($rules->isUnique(['id_number', 'client_id'], 'The Number you selected is in use, please use another'));
        return $rules;
    }
}

但是构建规则无法限制此重复项,因为第一个代码片段中 beforeFind() 中提到的代码导致 isUnique() 仅检查 getUserLocationIds() 返回的条目。

我想知道如何使 beforeFind() 中的逻辑不适用于 buildRules() 中的函数调用?或者是否有更好的方法来做到这一点?

额外问题:我是否应该在 MySQL 以及 CakePHP 中验证此规则? CakePHP 应用程序中此类事情的最佳实践是什么?

谢谢!

编辑:我还不是 100% 确定,但经过进一步检查,这个问题可能与 CakePHP 中的错误有关,而不是代码的实现。我发布了以下 issue on GitHub.

我不会说这是一个错误,它看起来更像是我的预期行为,毕竟 beforeFind 会影响所有 ORM 查询。

如果规则会忽略 beforeFind 修改(这将是一件有点复杂的事情),那么这会给另一端带来很多问题,即对于 想要应用查询修改。

恕我直言,目前最简洁的方法是使用 custom finder that applies the location restrictions, and then you explicitly use it where you want it to be used, or to use a custom/extended rule where you can pass query options,您的 beforeFind 回调可以评估该过滤器,使过滤器成为可选的。

就核心而言,如果规则接受允许修改查询的回调,可能会有所帮助。

ps。恕我直言,是的,您还应该考虑向数据库添加适当的唯一索引 table,这样即使花哨的反馈应用程序规则失败也能确保数据完整性。