将涉及连接 table 的查询从 CakePHP 1.3 转换为 3

Translating query involving join table from CakePHP 1.3 to 3

我正在将应用程序从 Cake 1.3 迁移到 3.0。我的数据库有团队和人员(teams_people 通过 belongsToMany 关系连接他们)和部门(团队属于部门)。 teams_people table 有额外的信息,比如这个人在球队中的角色(队长,球员),球衣号码,位置,诸如此类。在下面的示例中,我正在尝试读取一个人所在的公开组中的团队列表,包括他们的位置等。

$teams = $this->Teams->find()
    ->select(['teams_people.*'])
    ->autoFields(true)
    ->contain(['Divisions'])
    ->leftJoin(
        ['teams_people'],
        ['teams_people.team_id = Teams.id']
    )
    ->where([
        'Divisions.is_open' => true,
        'teams_people.person_id' => $id,
    ]);

这是我能找到的 Cake 1.3 查询最直接的翻译,但它不会工作,因为 "teams_people.*" 通配符是 1.3 的一部分。 (这在 中进行了讨论。)如果我将 teams_people 列的整个列表放在那里,它工作正常,但在我稍后添加更多列并且不是 DRY 的情况下这是脆弱的。 (目前,为了让它工作,我有一个辅助函数来查看模式并构建所有列的列表。)我对新的 ORM 还是很陌生,我想学习 "right" 现在做事的方式,以便我需要转换的许多查询可以在第一时间以最佳方式完成,而不是让杂乱无章地根深蒂固。

我不需要有关人员的信息(姓名等),因为 Auth 组件已经加载了这些信息。这就是为什么我没有在这里的任何地方直接让人们 table 参与进来(删除它可以保存查询),这反过来又是为什么我需要指定 teams_people table 的连接。仅靠 autoFields 不足以从手动连接的 table 中提取字段,因此我需要 select 来指定这些字段。

我觉得会有一些很好的方法来做到这一点,也许通过 People table 对象但使用 "matching" 函数或其他一些方法来查询人们 table 从未真正发生过? "Cakiest" 处理这种情况的方法是什么?

在您的情况下,匹配似乎是可行的方法,您的 table 已正确关联,因此实际上不需要使用自定义联接和其他东西。

这是一个基于您给定查询的基本示例:

$teams = $this->Teams
    ->find()
    ->contain(['Divisions'])
    ->matching('People', function(\Cake\ORM\Query $query) use ($id) {
        return $query
            ->where([
                'People.id' => $id
            ]);
    }))
    ->where([
        'Divisions.is_open' => true
    ]);

ORM 将为 peopleteams_people table 创建适当的内部联接,并使用它们来过滤人员 $id 被分配到的团队。这一切都是通过单个查询中的内部连接完成的,看起来像

SELECT
    Teams.id AS `Teams__id`,
    ...,
    People.id AS `People__id`,
    ...,
    TeamsPeople.id AS `TeamsPeople__id`,
    TeamsPeople.team_id AS `TeamsPeople__team_id`,
    TeamsPeople.person_id AS `TeamsPeople__person_id`,
    ...,
    Divisions.id AS `Divisions__id`,
    ...
FROM
    teams Teams 
INNER JOIN
    people People 
        ON People.id = 1
INNER JOIN
    teams_people TeamsPeople 
        ON (
            Teams.id = (
                TeamsPeople.team_id
            ) 
            AND People.id = (
                TeamsPeople.person_id
            )
        ) 
INNER JOIN
    divisions Divisions 
        ON Divisions.id = (
            Teams.division_id
        ) 
WHERE
    Divisions.is_open = 1

来自联接 table 的数据将在特殊的 _matchingData 属性 中可用,它将在 TeamsPeople

中保存一个实体
$teamEntity->_matchingData['TeamsPeople']

另见 Cookbook > Database Access & ORM > Filtering by Associated Data