сортировка коллекций по подкатегории, атрибуту и ​​по названию товара

Я работаю над проблемой уже несколько часов, и, похоже, я не могу найти способ заставить работать вышеприведенную сортировку.

В проекте 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(). Я думаю, реализовать этот функционал будет непросто.


person Andreas W. Wylach    schedule 30.09.2013    source источник


Ответы (1)


Я не уверен, является ли это ожидаемым результатом, но, учитывая ваши критерии, следующее ниже установит коллекцию так, как вам нужно?

$products = Mage::getModel( 'catalog/product' )
    ->getCollection()
    ->addAttributeToSelect( '*' )
    ->addFieldToFilter( 'status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED )
    ->addFieldToFilter( 'visibility', Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH );
    ->addAttributeToFilter( 'category_id', array( 'in' => array( 'finset' => '[CATEGORY_ID_HERE]' ) ) );
    ->addAttributeToSort( 'category_id', ASC )
    ->addAttributeToSort( 'ws_geschmack', ASC )
    ->addAttributeToSort( 'name', ASC );

Вы можете использовать аналогичные методы, чтобы сузить свою коллекцию и упростить вещи. Также знайте, что если вы настраиваете встроенные методы сбора продуктов, сортировщик во внешнем интерфейсе может изменять ваш внешний интерфейс, поэтому вы можете убедиться, что он не влияет на него.

person Jason    schedule 30.09.2013
comment
Спасибо за ответ, Джейсон. Я тоже думал об этом, и это было бы самым простым, но сортировка категорий будет по идентификатору, а не по фактической строке категории, представляющей этот идентификатор. Кроме того, я думаю, что addAttributeToFilter должен выполнять операцию «ИЛИ» для всех идентификаторов категорий и подкатегорий (все они is anchored!), Это возможно, а не проблема. Но и здесь основная проблема все еще не решена, поскольку она сортируется по числовому идентификатору. - person Andreas W. Wylach; 01.10.2013