Magento 2: Как работают граненые данные для многоуровневой навигации?

10

Я создал модуль для пользовательского фильтра на странице категории, все работает нормально, кроме ценового диапазона в многоуровневой навигации.

Пожалуйста, кто-нибудь может объяснить мне, как getFacetedData ('цена') работает в magento2

$productCollection->getFacetedData('price');

Эта функция дает мне диапазоны цен, основанные на коллекции продуктов по умолчанию, а не на моей отфильтрованной коллекции.

К вашему сведению: я отфильтровал коллекцию, как показано ниже,

$productCollection = $layer->getProductCollection()
->clear()
->addAttributeToSelect(['name','price'])
->addAttributeToFilter('sku', array('in' => ['sku1','sku2']));
Налин савалия
источник

Ответы:

7

Код ниже относится к Magento 2.2.5.

Прежде всего, на боковой панели должны быть указаны все возможные диапазоны для всех возможных фильтров. Кроме того, для этого у вас будет обзор количества продуктов, найденных в данном диапазоне.

введите описание изображения здесь

Например, я сосредоточусь на использовании одного фильтра: цены.

Прежде всего, чтобы данный атрибут продукта имел право на многоуровневую навигацию, он должен быть правильно настроен.

Для проверки перейдите в админку Stores -> Attribute -> Product, затем выберите атрибут цены и обратите внимание, что на Storefront Propertiesвкладке Use in Layered Navigationустановлено значениеFilterable (with results)

На этой картинке мы видим, что для ценового фильтра мы видим диапазон, 50.00-59.99содержащий 10результаты, и 80+только для 1.

Этот вид создается внутри

/vendor/magento/theme-frontend-luma/Magento_LayeredNavigation/templates/layer/view.phtml

Есть код, похожий на

<?php foreach ($block->getFilters() as $filter): ?>
    <?php if ($filter->getItemsCount()): ?>

Который в конечном итоге складывается до

private function prepareData($key, $count)

и это метод из

vendor/magento/module-catalog-search/Model/Layer/Filter/Price.php

Итак, мы определили класс, который отвечает за фильтрацию цен, и мы видим, что он уже использовался для создания доступных диапазонов.


Более важным стеком является проверка того, что происходит при выборе определенного диапазона.

Например, я нажму на диапазон 40.00-49.99, который, как ожидается, вернет 4 результата.

Сначала это метод _prepareLayout()из

/vendor/magento/module-layered-navigation/Block/Navigation.php

Код

protected function _prepareLayout()
{
    foreach ($this->filterList->getFilters($this->_catalogLayer) as $filter) {
        $filter->apply($this->getRequest());
    }
    $this->getLayer()->apply();
    return parent::_prepareLayout();
}

По сути, это говорит о том, чтобы получить все фильтры и foreach из них сделать apply.

Теперь только getFilters () в конечном итоге приводит к созданию объекта из

vendor/magento/module-catalog-search/Model/Layer/Filter/Price.php

Вызывающий шаг , который ведет к __constructиз PriceIS

protected function createAttributeFilter(
    \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute,
    \Magento\Catalog\Model\Layer $layer
) {
    $filterClassName = $this->getAttributeFilterClass($attribute);

    $filter = $this->objectManager->create(
        $filterClassName,
        ['data' => ['attribute_model' => $attribute], 'layer' => $layer]
    );
    return $filter;
}

И это код из

vendor/module-catalog/Model/Layer/FilterList.php

В любом случае, если мы вернемся к $filter->apply($this->getRequest());коду сверху, это означает, что этот код будет выполнен

public function apply(\Magento\Framework\App\RequestInterface $request)
{
    /**
     * Filter must be string: $fromPrice-$toPrice
     */
    $filter = $request->getParam($this->getRequestVar());
    if (!$filter || is_array($filter)) {
        return $this;
    }

    $filterParams = explode(',', $filter);
    $filter = $this->dataProvider->validateFilter($filterParams[0]);
    if (!$filter) {
        return $this;
    }

    $this->dataProvider->setInterval($filter);
    $priorFilters = $this->dataProvider->getPriorFilters($filterParams);
    if ($priorFilters) {
        $this->dataProvider->setPriorIntervals($priorFilters);
    }

    list($from, $to) = $filter;

    $this->getLayer()->getProductCollection()->addFieldToFilter(
        'price',
        ['from' => $from, 'to' =>  empty($to) || $from == $to ? $to : $to - self::PRICE_DELTA]
    );

    $this->getLayer()->getState()->addFilter(
        $this->_createItem($this->_renderRangeLabel(empty($from) ? 0 : $from, $to), $filter)
    );

    return $this;
}

и снова этот код из

vendor/magento/module-catalog-search/Model/Layer/Filter/Price.php

Если я внимательно слежу за значениями переменных, опять же, учитывая, что я выбрал диапазон 40.00-49.99, то $filterмассив состоит из двух элементов: [0 => 40, 1 => 50]

После того, как эта строка выполнена

list($from, $to) = $filter;

Очевидно, что $fromпеременная теперь 40, а $toпеременная теперь 50.

Следующая строка имеет решающее значение

    $this->getLayer()->getProductCollection()->addFieldToFilter(
        'price',
        ['from' => $from, 'to' =>  empty($to) || $from == $to ? $to : $to - self::PRICE_DELTA]
    );

Это где уже существующая коллекция, связанная с Layer, дополнительно сокращается путем вызова addFieldToFilter().

Возможно, именно на это следует обратить внимание, чтобы обнаружить ошибки, если они есть.

В конце концов, программа вызывает getLoadedProductCollection () из

vendor/magento/module-catalog/Block/Product/ListProduct.php

который в efect возвращает защищенную коллекцию, которую этот объект инкапсулирует.


Magento - сложное приложение.

В этом единственном щелчке, который выбрал один единственный диапазон цен, мы увидели код из трех разных модулей, взаимодействующих

  • модуль-каталог
  • модуль-каталог-поиск
  • модуль-слоисто-навигация

Временами это может показаться ошеломляющим, но мне кажется, что между этими модулями есть хорошая синергия.

Спасибо за чтение. Я надеюсь, что это объясняет, и вы теперь немного лучше разбираетесь в многоуровневой навигации.

Марьян
источник
+1 за очень подробный и красиво объясненный ответ. Однако вы не объяснили, как работают граненые данные ... Граненые данные используются для генерации счетчиков фильтров.
Йонн Триморо
Привет @Marjan, в моем случае категория третьего уровня не отображается в фильтре, вот мой вопрос, magento.stackexchange.com/questions/270442/…
jafar pinjar