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

时间:2019-06-17 09:45:12

标签: php cakephp cakephp-3.0 cakephp-3.x

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

我们有3个具有以下层次结构的数据库表。这些表根据表类正确关联:

  • regulations
    • groups
      • filters

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

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

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

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

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

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

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

我已经在Cake文档中阅读了How to paginate associated records?Filtering By Associated Data

其他信息

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

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编写它,它将返回一个表,该表只有3列带有需要显示的标签。就在页面上输出所需数据而言,此结构更容易使用。

  2. 第二个-也许是更重要的问题-我无法看到您如何在ORM语法中编写LIMIT条件来使此工作有效,原因是1中描述的嵌套结构。例如,如果我添加了$data->limit(50),它只会对regulations表施加此限制。因此,本质上来说,该搜索对regulations中前50行中的任何相关数据有效。与我在MySQL中编写的LIMIT条件相反,该条件将考虑包括所有3个表中的列在内的整个结果集。

为进一步阐述第二点,假设表包含以下行数:

  • regulations:150
  • groups:1000
  • filters:5000

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

1 个答案:

答案 0 :(得分:1)

使用查询生成器创建该查询非常简单,如果您想加入非1:1关联的联接,则使用*JoinWith()方法代替contain(),在这种情况下为{{1} },例如:

innerJoinWith()

另请参见