在 CakePHP 3 中使用动态 AJAX 加载分页和搜索关联查询

Paginate and search associated query with dynamic AJAX loading in CakePHP 3

我正在使用 CakePHP 3.7 开发应用程序。

我们有 3 个数据库 table,具有以下层次结构。这些 table 根据 Table 类:

正确关联

(关联在上一个问题中显示:CakePHP 3 - association is not defined - even though it appears to be

我可以从所有三个 table 中获取所有数据,如下所示:

$regulations = TableRegistry::getTableLocator()->get('Regulations');
$data = $regulations->find('all', ['contain' => ['Groups' => ['Filters']]]);
$data = $data->toArray();

filters table 包含 >1300 条记录。因此,我正在尝试构建一个功能,当用户向下滚动页面时,通过 AJAX 调用逐步加载数据,类似于此处描述的内容:https://makitweb.com/load-content-on-page-scroll-with-jquery-and-ajax/

问题是我需要能够计算返回的总行数。但是,此数据存在于 3 table 秒内。

如果我执行 debug($data->count());,它将输出 8,因为 regulations table 中有 8 行。理想情况下,我需要计算它在 filters table(~1300 行)中返回的行数,就初始负载而言,这是大多数数据存在的地方。

问题更加复杂,因为此功能允许用户执行搜索。给定的搜索词可能存在于所有 3 个 table 中,table 中的 1 - 2 个中,或者根本不存在。我不知道这样做的正确方法是尝试计算每个 table 中返回的行数还是总体行数?

我已阅读 Cake 文档中的 and Filtering By Associated Data

附加信息

问题似乎归结为如何使用 Cake 提供的 ORM 语法编写查询。以下(纯 MySQL)查询实际上会执行我想要的操作。假设用户搜索了 "Asbestos":

SELECT
regulations.label AS regulations_label,
groups.label AS groups_label,
filters.label AS filters_label
FROM
groups
JOIN regulations
ON groups.regulation_id = regulations.id 
JOIN filters
ON filters.group_id = groups.id
WHERE regulations.label LIKE '%Asbestos%'
OR groups.label LIKE '%Asbestos%'
OR filters.label LIKE '%Asbestos%'
ORDER BY
regulations.id ASC,
groups_label ASC,
filters_label ASC
LIMIT 0,50

假设返回了 203 行。 LIMIT 条件意味着我得到前 50 个。前端的一些 js(就其工作方式而言并不真正相关)将在用户滚动到底部时进行 ajax 调用重新 运行 具有不同限制的此查询(例如 LIMIT 51, 100 用于下一组结果)。

问题似乎有两个方面:

  1. 如果我使用 Cake 的 ORM 语法编写查询,则输出是一个嵌套数组。相反,如果我用普通的 SQL 编写它,它会返回一个 table,它只有 3 列,其中包含我需要显示的标签。就在页面上输出所需数据而言,这种结构更容易使用。

  2. 第二个 - 也许 更重要的问题 - 是我看不出你如何在 ORM 中编写 LIMIT 条件由于 1 中描述的嵌套结构,语法使这项工作有效。例如,如果我添加 $data->limit(50),它只会对 regulations table 施加此限制。因此,本质上搜索适用于 regulations 中前 50 行的任何关联数据。与我在 MySQL 中编写的 LIMIT 条件相反,它会考虑整个结果集,其中包括来自所有 3 个 table 的列。

为了进一步阐述第 2 点,假设 table 包含以下行数:

如果我使用 $data->limit(50),它将仅适用于 regulations table 中的 50 行。我需要在所有 3 table 中搜索给定术语的所有行后应用 LIMIT 结果集。

使用查询生成器创建该查询非常简单,如果您想要连接非 1:1 关联,则使用 *JoinWith() 方法而不是 contain(),在本例中为 innerJoinWith(),类似于:

$query = $GroupsTable
    ->find()
    ->select([
        'regulations_label' => 'Regulations.label',
        'groups_label' => 'Groups.label',
        'filters_label' => 'Filters.label',
    ])
    ->innerJoinWith('Regulations')
    ->innerJoinWith('Filters')
    ->where([
        'OR' => [
            'Regulations.label LIKE' => '%Asbestos%',
            'Groups.label LIKE' => '%Asbestos%',
            'Filters.label LIKE' => '%Asbestos%',
        ],
    ])
    ->order([
        'Regulations.id' => 'ASC',
        'Groups.label' => 'ASC',
        'Filters.label' => 'ASC',
    ]);

另见