Как мне объединить две таблицы в третьем отношении n ..n (hasAndBelongsToMany) в CakePHP?
-
02-07-2019 - |
Вопрос
У меня есть n...n
структура для двух таблиц, makes
и models
.Пока никаких проблем.
В третьей таблице (products
) нравится:
id
make_id
model_id
...
Моя проблема заключается в создании представления для продуктов одного конкретного типа. make
внутри моего ProductsController
содержащий только то, что создает модели:
Я думал, это может сработать:
var $uses = array('Make', 'Model');
$this->Make->id = 5; // My Make
$this->Make->find(); // Returns only the make I want with it's Models (HABTM)
$this->Model->find('list'); // Returns ALL models
$this->Make->Model->find('list'); // Returns ALL models
Итак, если я хочу использовать list
чтобы перейти к моему представлению для создания переключателей, мне нужно будет выполнить foreach()
в моем make
массив для поиска названий всех моделей, создания нового массива и отправки на просмотр через $this->set()
.
$makeArray = $this->Make->find();
foreach ($makeArray['Model'] as $model) {
$modelList[] = $model['title'];
}
$this->set('models', $models)
Есть ли какой-нибудь более простой способ получить этот список, не подчеркивая make
Массив.Разработка таких сценариев в моих приложениях будет обычной задачей.
Заранее спасибо за любую подсказку!
Решение 5
Решение может быть достигнуто с помощью with
операция в массиве habtm над моделью.
Используя with
вы можете определить "среднюю" таблицу следующим образом:
$habtm = " ...
'with' => 'MakeModel',
... ";
И внутренне, в Модели или контроллере, вы можете выдавать условия для find
способ.
Другие советы
Вот моя подсказка:Попробуйте записать свой запрос на обычном SQL, прежде чем пытаться реконструировать его с помощью библиотеки Cake.По сути, вы выполняете много дополнительной работы, которую база данных может выполнить за вас.Ваш подход (просто для галочки - не очень хороший SQL):
SELECT * FROM makes, models, products WHERE make_id = 5
Вы не принимаете во внимание взаимосвязи (если только Cake автоматически не понимает взаимосвязи таблиц)
Вероятно, вы ищете что-то, что объединяет эти вещи воедино:
SELECT models.title FROM models
INNER JOIN products
ON products.model_id = models.model_id
AND products.make_id = 5
Надеюсь, это толчок в правильном направлении?
Судя по вашему комментарию, вы спрашиваете, как получить результаты от определенной модели, где условие находится в модели, связанной с HABTM.То есть.то, что вы обычно делаете с оператором JOIN в необработанном SQL.
В настоящее время это одно из немногих слабых мест Cake.Существуют различные стратегии, чтобы справиться с этим.
Попросите связанную модель B вернуть все идентификаторы возможных кандидатов для модели A, затем выполните второй запрос для модели A.То есть.:
$this->ModelB->find('first', array('conditions' => array('field' => $condition))); array( ['ModelB'] => array( ... ), ['ModelA'] => array( [0] => array( 'id' => 1 ) )
Теперь у вас есть массив всех идентификаторов ModelA, принадлежащих ModelB, который соответствует вашим условиям, который вы можете легко извлечь с помощью Set::extract() .По сути, эквивалент
SELECT model_a.id FROM model_b JOIN model_a WHERE model_b.field = xxx
.Далее вы ищете модель:$this->ModelA->find('all', array('conditions' => array('id' => $model_a_ids)));
Это приведет к
SELECT model_a.* FROM model_a WHERE id IN (1, 2, 3)
, что является обходным способом выполнения инструкции JOIN .Если вам нужны условия для более чем одной связанной модели, повторяйте до тех пор, пока у вас не будут все идентификаторы для ModelA, SQL будет использовать пересечение всех идентификаторов (WHERE id IN (1, 2, 3) AND id IN (3, 4, 5)
).Если вам нужно только одно условие для ModelB, но вы хотите получить ModelA, просто найдите ModelB.Cake автоматически извлекет для вас соответствующие модели (см. Выше).Возможно, вам потребуется установить ::extract() их снова, но этого уже может быть достаточно.
Вы можете использовать описанный выше метод и комбинировать его с Сдерживаемое поведение чтобы получить больше контроля над результатами.
Если все остальное не удается или описанные выше методы просто приводят к слишком большим накладным расходам, вы все равно можете написать свой собственный необработанный SQL с помощью
$this->Model->query()
.Если вы придерживаетесь стандартных стандартов SQL (правильное именование таблиц сFROM model_as AS ModelA
) Cake по-прежнему будет корректно обрабатывать ваши результаты после обработки.
Надеюсь, это направит вас в правильном направлении.
Все ваши различные вызовы Make->find() и Model-> find() полностью независимы друг от друга.Даже если Make-> Model-> find() совпадает с Model-> find(), Cake никоим образом не запоминает и не учитывает то, что вы уже нашли в других моделях.То, что вы ищете, это что-то вроде:
$this->Product->find('all', array('conditions' => array('make_id' => 5)));
Проверьте метод Set::extract() для получения списка названий моделей из результатов $this->Make->find()