Вопрос

TL; DR: Как отфильтровать несколько атрибутов SELECT/DUPDOWN (мульти-выборы были бы громоздкими)? Или использовать другой метод?

Рассмотрим атрибут выбора продукта/раскрывающегося списка, значения которого соответствуют каждой букве алфавита (английский в данном случае). Ярлык первого варианта - «A», его значение - 1. «B» - 2, «C» - 3, и т. Д.

У меня есть этот атрибут, назначенный для управления слоистыми навигационными фильтрами. Таким образом, пользователь может щелкнуть по ссылке для определенного значения, и он добавит ?my_attribute=2 в параметры запроса, и в списке продуктов показаны только продукты, значение атрибута, значение атрибута - «B».

Вместо этого я хотел бы отобразить любые продукты, которые значения атрибута больше или равны выбранной опции. Таким образом, в случае, если пользователь нажимает на ссылку «B» в слоистом нависе, результатами будут каждый продукт от «BZ» (2-26).

Структура URL: ?my_attribute=2&my_attribute_3&my_attribute=4... было бы уродливым и, кроме того, это не работает, но идея есть. ?my_attribute=2-26 Очевидно, было бы идеальным, но опять же, это не то, что делает Magento.

Любопытно, что использование Advanced Search обеспечивает эту структуру URL -адреса (через расширенный контроллер поиска вместо слоистых навие):

?my_attribute%5B%5D=7&my_attribute%5B%5D=8&my_attribute%5B%5D=9&my_attribute%5B%5D=10

Это действительно дает желаемые результаты; Тем не менее, эта структура не работает с категориями/слоистыми страницами, только расширенный поиск.

Я пытаюсь решить, какой будет лучший путь на этом этапе; Должен ли я отказаться от всей встроенной полезности слоистой навигации и вместо этого переписать product_list Блок загруженный сборник продуктов на основе моего значения атрибута? Или я должен адаптировать некоторые функциональные возможности из расширенных результатов поиска, чтобы соответствовать моим потребностям?

Похоже, было бы лучше оставить многослойную навигационную функциональность в одиночку, чтобы другие фильтры продукта продолжали работать, как и ожидалось; Но, похоже, не позволит выбрать несколько значений из одного атрибута одновременно. В качестве альтернативы, обходной путь заключается в том, чтобы использовать многоцелевой атрибут, и если бы продукт будет назначен «B», ему нужно будет назначить все варианты из «BZ». Несмотря на то, что это дало бы наибольшие мгновенные результаты (все будет работать без больших модификаций), это, безусловно, неряшливое решение, которое будет подвержено ошибкам и неуклюжим в будущем.

Это было полезно?

Решение

В этом случае я сделал переписать как модель, так и соответствующий ресурс, так что сначала перепишите класс Mage_Catalog_Model_Layer_Filter_Attribute иметь возможность принимать несколько значений. В моем случае я использую запятые в качестве сепаратора, поэтому я могу фильтровать как ?my_attribute=1,2,3

В методе apply() Я анализирую атрибут, чтобы поместить различные значения в массив:

  public function apply(Zend_Controller_Request_Abstract $request, $filterBlock)
    {
        $filter = $request->getParam($this->_requestVar);
        if (is_array($filter)) {
            return $this;
        }

        // MP customized
        $filter = explode(',', $filter);
        if (count($filter) < 1) {
            return $this;
        } else if ($filter == '') {
            return $this;
        }

        if (count($filter) == 1) {
            $filter = $filter[0];
        }

        if ($filter == '') {
            return $this;
        }

        if ($filter) {
            $this->_initItems();
            $this->_getResource()->applyFilterToCollection($this, $filter);
            $text = '';
            foreach ($filter as $att) {
                ($text == '') ? $text = $this->_getOptionText($att) : $text .= ', '.$this->_getOptionText($att);
            }
            if (count($filter) == 1) {
                $text = $this->_getOptionText($filter);
            }
            $this->getLayer()->getState()->addFilter($this->_createItem($text, $filter));
        }
        // End MP customized
        return $this;
      }

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

     public function applyFilterToCollection($filter, $value)
    {
        $collection = $filter->getLayer()->getProductCollection();
        $attribute  = $filter->getAttributeModel();
        $connection = $this->_getReadAdapter();
        $tableAlias = $attribute->getAttributeCode() . '_idx';
        $conditions = array(
            "{$tableAlias}.entity_id = e.entity_id",
            $connection->quoteInto("{$tableAlias}.attribute_id = ?", $attribute->getAttributeId()),
            $connection->quoteInto("{$tableAlias}.store_id = ?", $collection->getStoreId()),
            $connection->quoteInto("{$tableAlias}.value IN (?)", $value)
        ); // Added IN (?) notation for arrays


        $collection->getSelect()->join(
            array($tableAlias => $this->getMainTable()),
            join(' AND ', $conditions),
            array()
            // MP Need distinct here to avoid getting the same config product from
            // different basic products when filtering for different values
            // in the same attribute
        )->distinct(true);

        return $this;
    }

Другие советы

Вот многослойная навигация с пользовательской коллекцией продуктов

<?php
    require_once('app/Mage.php'); //Must have file to begin

    Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID); //Initialize store

    $catId = Mage::app()->getRequest()->getParam('categoryId'); //Pass categoryId in get variable
        $storeId = Mage::app()->getWebsite(true)->getDefaultGroup()->getDefaultStoreId();
        $page_no = Mage::app()->getRequest()->getParam('page_no');
        $params = Mage::app()->getRequest()->getParams(); //Pass attributes in key=>value form to filter results.
        $category = Mage::getModel('catalog/category')->load($catId);

        $layer = Mage::getModel("catalog/layer");
        $layer->setCurrentCategory($category);
        $attributes = $layer->getFilterableAttributes(); //get all filterable attributes available in selected category layered navigation
        $attr = array();
        foreach ($attributes as $attribute) {
            if ($attribute->getAttributeCode() == 'price') {
                $filterBlockName = 'catalog/layer_filter_price';
            } elseif ($attribute->getBackendType() == 'decimal') {
                $filterBlockName = 'catalog/layer_filter_decimal';
            } else {
                $filterBlockName = 'catalog/layer_filter_attribute';
            }
            $attr[$attribute->getAttributeCode()] = $attribute->getFrontendLabel();

        }
        $filters = array_intersect_key($params, $attr);
        $collection = $category->getProductCollection()
                        ->addAttributeToFilter(
                            'status', array('eq' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED))
                        ->addAttributeToSelect('*');
        foreach ($filters as $key => $value) {
            if($key == 'price'){
                $priceFilter = explode('-', $value);
                $collection->addAttributeToFilter('price', array('gteq' => $priceFilter[0]));
                $collection->addAttributeToFilter('price', array('lteq' => $priceFilter[1]));
            }
            else{
$codeId = Mage::getResourceModel('eav/entity_attribute')
    ->getIdByCode('catalog_product', $key)
$collection->getSelect()->join(array('at_'.$key =>'catalog_product_index_eav'),'at_'.$key.'.entity_id = e.entity_id and at_'.$key.'.attribute_id = '.$codeId.' and at_'.$key.'.store_id = '.Mage::helper('mobile')->getStore()->getId())->where('at_'.$key.'.value = '.$value);
            }
        }
        $collection->setPage($page_no, 10);
    foreach($collection as $product){
       echo $product->getName();
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с magento.stackexchange
scroll top