如何确保开发人员通过 CakePHP 中的外键进行过滤

How to ensure developers filter by a foreign key in CakePHP

在遗留项目中,如果开发人员忘记查询条件中的 project_id,则会显示所有项目的行,而不是他们本应看到的单个项目。例如 "Comments":

 comments [id, project_id, message ]

如果您忘记按 project_id 过滤,您会看到所有项目。这是通过测试捕获的,有时不是,但我宁愿做一个预防 - 开发人员应该直接看到 "WRONG/Empty"!

为了解决这个问题,产品经理坚持使用单独的评论表,如下所示:

 project1_comments [id,message]
 project2_comments [id,message]

在这里,如果您忘记了 project/table 名称,如果某些内容仍然通过测试并已部署,您将一无所获或出现错误。

然而,困难在于关联表。示例 "Files" 链接到 "Comments":

files [ id, comment_id, path ]
    3,     1,   files/foo/bar

project1_comments
id    |   message
1     |  Hello World

project2_comments
id    |   message
1     |  Bye World

这会变成每个项目一个数据库,这似乎有点过分了。

另一种可能性,如何在 Comments 模型上添加行为以确保任何 find/select 查询都包含外键,例如 - project_id?

非常感谢。

In a legacy project we had issues where if a developer would forget a project_id in the query condition

CakePHP 根据您为 table 定义的关联生成连接条件。当您使用 contains 时,它们是 automatic 并且开发人员不太可能在 CakePHP 中犯这样的错误。

To get around this, the product manager is insisting on separate tables for comments, like this:

不要这样做。对我来说这真是个坏主意。

Another possibility, how to add a Behaviour on the Comments model to ensure any find/select query does include the foreign key, eg - project_id?

最简单的解决方案是禁止对 Comments table.

的所有直接查询
class Comments extends Table {
    public function find($type = 'all', $options = [])
    {
         throw new \Cake\Network\Exception\ForbiddenException('Comments can not be used directly');
    }
}

此后只允许 Comments 通过关联读取(关联始终具有有效的连接条件),但在这样做之前请三思,因为我看不出这样的限制有任何好处。

您不能轻易地将对 Comments 的直接查询限制为仅那些在 where 子句中包含 product_id 的查询。问题是 where 子句是一个表达式树,您必须遍历树并检查所有不同类型的表达式。好痛。

我会做的是限制 Comments 以便 product_id 必须作为选项传递给查找器。

 $records = $Comments->find('all', ['product_id'=>$product_id])->all();

上面所做的是将 $product_id 作为选项传递给 table 的默认 findAll 方法。我们可以覆盖该方法并强制 product_id 作为 必需的 选项 all 直接评论查询。

public function findAll(Query $query, array $options)
{
    $product_id = Hash::get($options, 'product_id');
    if (!$product_id) {
        throw new ForbiddenException('product_id is required');
    }
    return $query->where(['product_id' => $product_id]);
}

我没有看到通过行为执行上述操作的简单方法,因为 where 子句在执行行为时仅包含表达式。