Вот логика, которую я придумал, чтобы решить эту проблему.
Примечание. Должно работать в Magento 1.X
- . Оно динамически извлекает имена таблиц, чтобы оно работало в любой установке.
- Проверяет, что этоправильный
catalog/category
идентификатор объекта. - Используется уникальный псевдоним таблицы по идентификатору категории при выполнении MySQL LEFT JOIN.Это позволяет нам исключить коллекцию из нескольких идентификаторов категорий.
Это подтверждает, что мы не пытаемся исключить коллекцию из одного и того же идентификатора категории дважды.
public function addCategoryExclusionFilter(Mage_Catalog_Model_Resource_Product_Collection $collection, $category_id)
{
/* @var $resource Mage_Core_Model_Resource */
/* @var $category Mage_Catalog_Model_Category */
$resource = Mage::getModel('core/resource');
$category = Mage::getModel('catalog/category')->load($category_id);
$select = $collection->getSelect();
$tblccp = $resource->getTableName('catalog_category_product');
$tblAlias = $tblccp.'_'.$category_id;
if (! $category->getId()) {
Mage::throwException("Invalid `{$resource->getTableName('catalog/category')}`.`entity_id` value ({$category_id}).");
}
if (strpos($select->__toString(), $tblAlias) !== false) {
Mage::throwException("Category (ID: {$category->getId()}) already excluded from collection");
}
$select->joinLeft(array($tblAlias => $tblccp), "(`{$tblAlias}`.`product_id` = `e`.`entity_id` AND `{$tblAlias}`.`category_id` = '{$category->getId()}')", array());
$select->where("`{$tblAlias}`.`category_id` IS NULL");
}
Пример запроса MySQL впоследствии:
SELECT
`e`.*
FROM
`catalog_product_entity` AS `e`
LEFT JOIN
`catalog_category_product` AS `catalog_category_product_28` ON (
`catalog_category_product_28`.`product_id` = `e`.`entity_id` AND
`catalog_category_product_28`.`category_id` = '28'
)
WHERE
(`catalog_category_product_28`.`category_id` IS NULL)
Здесь мы выполняем соединение таблицы, в которой хранятся отношения между сущностями продукта и сущностями категории, НО только там, где запись category_id
равен идентификатору категории, который мы хотим исключить.Это важно, потому что таблица catalog_product_entity
имеет отношение 1: M к таблице catalog_category_product
(на момент публикации этого ответа я не вижу здесь других ответов на этот вопрос).Затем мы добавляем декларацию WHERE, в которой нам нужно только выбрать записи, в которых столбец category_id
для объединенной таблицы равен NULL (поскольку в объединенной таблице нет записей для сущностей продуктов, которые мы хотим выбрать).