Я работаю над проблемой уже несколько часов, и, похоже, я не могу найти способ заставить работать вышеприведенную сортировку.
В проекте magento (я относительно новичок в magento) я должен сначала отсортировать коллекцию по подкатегории, затем по атрибуту и, наконец, по названию продукта. is Anchor
установлен для всех категорий, поэтому в родительских категориях также отображаются продукты подкатегорий.
Я наткнулся на идею использования ReflectionObject
с помощью функции usort()
PHP с функцией сравнения, например:
private static function cmp($a, $b) {
$a_product_geschmack = Mage::getModel('catalog/product')
->load($a->getId())->getAttributeText('ws_geschmack');
$b_product_geschmack = Mage::getModel('catalog/product')
->load($b->getId())->getAttributeText('ws_geschmack');
$r = strcmp(get_category($a), get_category($b));
if ($r != 0)
return $r;
$r = strcmp($a_product_geschmack, $b_product_geschmack);
if ($r != 0)
return $r;
return strcmp($a->getName(), $b->getName());
}
Вспомогательная функция для получения подкатегории выглядит так:
function get_category($product) {
$categoryModel = Mage::getModel( 'catalog/category' );
// Get Array of Category Id's with Last as First (Reversed)
$_categories = array_reverse( $product->getCategoryIds() );
// Get Parent Category Id
$_parentId = $categoryModel->load($_categories[0])->getParentId();
// Load Parent Category
$_category = $categoryModel->load($_parentId);
return $_category->getName();
}
Используя приведенный выше компаратор с usort и ReflectionObject в методе _getProductCollection()
Mage_Catalog_Block_Product_List
:
// ...
$collection = $this->_productCollection;
$collectionReflection = new ReflectionObject($collection);
$itemsPropertyReflection = $collectionReflection->getProperty('_items');
$itemsPropertyReflection->setAccessible(true); // Make it accessible
$collectionItems = $itemsPropertyReflection->getValue($collection);
usort($collectionItems, array('Mage_Catalog_Block_Product_List', 'cmp'));
$itemsPropertyReflection->setValue($collectionReflection, $collectionItems);
$itemsPropertyReflection->setAccessible(false); // Return restriction back
$this->_productCollection = $collection;
// ...
Все вышеперечисленное я установил в качестве теста (чтобы проверить, работает ли оно) в классе Mage_Catalog_Block_Product_List
. Для безопасности я закомментировал настройку сортировки по умолчанию с помощью setOrder
в Toolbar.php
.
Приведенный выше код я нашел по адресу https://magento.stackexchange.com/questions/5438/on-search-result-group-products-by-category, и это казалось многообещающим (даже если это больше хак, чем OO).
Когда я печатаю $collectionItems
, порядок соответствует ожидаемому. Во внешнем интерфейсе это не так, как ожидалось, например, атрибут ws_geschmack
не отсортирован, а также подкатегория не отсортирована «правильно».
Я также спрашиваю себя, является ли путь, возвращающий $collection
члену _productCollection
, правильным путем (как в примере кода, найденном в ответе stackexchange). Выяснил, что в классе ReflectionObject
тоже есть метод под названием setValue
, но тоже не работает.
Что ж, проблема не была бы настоящей проблемой, если бы подкатегория была атрибутом, в этом случае я мог бы просто использовать setOrder
с массивом полей для сортировки в порядке ASC.
Кроме того, порядок категорий в бэкэнде (если я упорядочиваю их в алфавитном порядке), похоже, не влияет. Если бы это сработало, я мог бы отказаться от сортировки по подкатегории.
Сортировка должна работать в списке продуктов категории и в списке результатов поиска, последнее не так важно, но просмотр категории важен.
Другие вопросы также похожи на мои (https://magento.stackexchange.com/questions/2889/sorting-product-list-by-more-than-one-attribute), но у этого парня были только атрибуты, и это можно решить с помощью setOrder
Call с использованием массива.
Так что у меня нет идей. У кого-нибудь есть идея, как решить эту проблему? Любая помощь приветствуется!
Я использую magento версии 1.7.0.2 для этого проекта.
Обновить
Просто чтобы уточнить, что я ищу: я реализовал этот итеративный код, который делает именно то, что мне нужно. Сначала он получает подкатегории текущей категории, а затем запрашивает все продукты в этих подкатегориях. Результатом является отсортированный список категорий, а результаты/подсписки товаров отсортированы по атрибуту ws_geschmack
и name
:
$categories = Mage::getModel('catalog/category')->getCollection()
->addAttributeToSelect('name')
->addFieldToFilter('parent_id',
array(
'eq' => Mage::getModel('catalog/layer')->getCurrentCategory()->getId()))
->addFieldToFilter('include_in_menu',array('eq' => '1'))
->addFieldToFilter('is_active', array('eq' => '1'))
->addAttributeToFilter('is_active', 1)
->addAttributeToSort('name', 'asc');
foreach($categories as $category) {
// Check if there are products for sale in this category
if (Mage::getModel('catalog/category')->load($category->getId())
->getProductCollection()
->addAttributeToSelect('entity_id')
->addAttributeToFilter('status', 1)
->addAttributeToFilter('visibility', 4)
->count() == 0) continue;
print "-> " . $category->getId() .': '. $category->getName() . "<br />";
// Get all child categories below this current category
$_subcategory_ids = get_categories(Mage::getModel('catalog/category')->getCategories($category->getId()));
// Build 'finset' query for category_id filter
$_subcategory_finset_ids = array_map(
function($elem) {
return array('finset' => $elem);
},
$_subcategory_ids);
$_products = Mage::getModel('catalog/product')
->getCollection()
->joinField('category_id', 'catalog/category_product', 'category_id', 'product_id = entity_id', null, 'left')
->addAttributeToSelect('*')
->addAttributeToFilter('status', 1)
->addAttributeToFilter('visibility', 4)
->addAttributeToFilter('is_saleable', array('like' => '1'))
->addAttributeToFilter('category_id', $_subcategory_finset_ids)
->addAttributeToSort('ws_geschmack', 'ASC')
->addAttributeToSort('name', 'ASC');
if ($_products->count() != 0) {
foreach ($_products as $_product) {
$prod = Mage::getModel('catalog/product')->load($_product->getId());
echo $prod->getName() . ": " . $prod->getAttributeText('ws_geschmack') . "<br />";
}
}
}
Это всего лишь демонстрационный код, я не могу использовать его как есть. Все, что мне нужно, например, в качестве возвращаемого значения из getLoadedProductCollection()
. Я думаю, реализовать этот функционал будет непросто.