Разбивка и поиск связанных запросов с динамической загрузкой AJAX в CakePHP 3 - PullRequest
0 голосов
/ 17 июня 2019

Я работаю над приложением в CakePHP 3.7.

У нас есть 3 таблицы базы данных со следующей иерархией.Эти таблицы связаны правильно в соответствии с классами таблиц:

  • regulations
    • groups
      • filters

(Ассоциации показаны в предыдущем вопросе: CakePHP 3 - ассоциация не определена - даже если она выглядит как )

Iможно получить все данные из всех трех таблиц следующим образом:

$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 docs.

Дополнительная информация

Проблема, похоже, сводится к тому, как написать запрос с использованием синтаксиса ORM, предоставляемого Cake.Следующий (обычный 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. Второй - и, возможно, более важный вопрос - это то, что я не вижу, как можно написать условие LIMIT в синтаксисе ORM, чтобы сделать этоработать из-за вложенной структуры, описанной в 1. Если я, например, добавил $data->limit(50), это только накладывает это ограничение на таблицу regulations.По сути, поиск работает для любых связанных данных в первых 50 строках в regulations.В отличие от условия LIMIT, которое я написал в MySQL, в котором учитывался бы весь набор результатов, включающий столбцы из всех трех таблиц.

Для дальнейшей проработки пункта 2,Предположим, что таблицы содержат следующие номера строк:

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

Если я использую $data->limit(50), это будет применяться только к 50 строкам в таблице regulations.Мне нужно применить LIMIT набор результатов после поиска всех строк во всех 3 таблицах для данного термина.

1 Ответ

1 голос
/ 20 июня 2019

Создать этот запрос с помощью построителя запросов довольно просто: если вы хотите объединения для ассоциаций не 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',
    ]);

См. Также

...