0

I have created a custom module to remove duplicate products from product listing page for that i have overridden the Magento\Catalog\Block\Product\ListProduct file using di.xml file. But the problem is when i override this file and modify the function initializeProductCollection() sorting is not working

following is my di.xml file Vendor\MultipleSeller\etc\di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Catalog\Block\Product\ListProduct" type="Vendor\MultipleSeller\Block\Product\ListProduct" />
<preference for="Magento\CatalogSearch\Block\SearchResult\ListProduct" type="Vendor\MultipleSeller\Block\Product\ListProduct" />

Following is my ListProduct.php file Vendor\MultipleSeller\Block\Product\ListProduct i have made only change in this function initializeProductCollection() all other code is copied from magento file

       namespace Vendor\MultipleSeller\Block\Product;

       use Magento\Catalog\Api\CategoryRepositoryInterface;
       use Magento\Catalog\Block\Product\ProductList\Toolbar;
       use Magento\Catalog\Model\Category;
       use Magento\Catalog\Model\Config;
       use Magento\Catalog\Model\Layer;
       use Magento\Catalog\Model\Layer\Resolver;
       use Magento\Catalog\Model\Product;
       use Magento\Catalog\Model\ResourceModel\Product\Collection;
       use Magento\Catalog\Pricing\Price\FinalPrice;
       use Magento\Eav\Model\Entity\Collection\AbstractCollection;
       use Magento\Framework\App\ActionInterface;
       use Magento\Framework\App\Config\Element;
       use Magento\Framework\Data\Helper\PostHelper;
       use Magento\Framework\DataObject\IdentityInterface;
       use Magento\Framework\Exception\NoSuchEntityException;
       use Magento\Framework\Pricing\Render;
       use Magento\Framework\Url\Helper\Data;


      class ListProduct extends 
      \Magento\Catalog\Block\Product\AbstractProduct implements 
      IdentityInterface
      {
/**
 * Default toolbar block name
 *
 * @var string
 */
protected $_defaultToolbarBlock = Toolbar::class;

/**
 * Product Collection
 *
 * @var AbstractCollection
 */
protected $_productCollection;

/**
 * Catalog layer
 *
 * @var Layer
 */
protected $_catalogLayer;

/**
 * @var PostHelper
 */
protected $_postDataHelper;

/**
 * @var Data
 */
protected $urlHelper;
protected $_helpermultiseller;
/**
 * @var CategoryRepositoryInterface
 */
protected $categoryRepository;

/**
 * @param Context $context
 * @param PostHelper $postDataHelper
 * @param Resolver $layerResolver
 * @param CategoryRepositoryInterface $categoryRepository
 * @param Data $urlHelper
 * @param array $data
 */
public function __construct(
    \Magento\Catalog\Block\Product\Context $context,
    PostHelper $postDataHelper,
    Resolver $layerResolver,
    \Magneto\MultipleSeller\Helper\Data $helperMultiSeller,
    CategoryRepositoryInterface $categoryRepository,
    Data $urlHelper,
    array $data = []
) {
    $this->_catalogLayer = $layerResolver->get();
    $this->_postDataHelper = $postDataHelper;
    $this->categoryRepository = $categoryRepository;
    $this->urlHelper = $urlHelper;
     $this->_helpermultiseller = $helperMultiSeller;
    parent::__construct(
        $context,
        $data
    );
}

/**
 * Retrieve loaded product collection
 *
 * The goal of this method is to choose whether the existing collection should be returned
 * or a new one should be initialized.
 *
 * It is not just a caching logic, but also is a real logical check
 * because there are two ways how collection may be stored inside the block:
 *   - Product collection may be passed externally by 'setCollection' method
 *   - Product collection may be requested internally from the current Catalog Layer.
 *
 * And this method will return collection anyway,
 * even when it did not pass externally and therefore isn't cached yet
 *
 * @return AbstractCollection
 */
protected function _getProductCollection()
{
    if ($this->_productCollection === null) {
        $this->_productCollection = $this->initializeProductCollection();
    }

    return $this->_productCollection;
}

/**
 * Get catalog layer model
 *
 * @return Layer
 */
public function getLayer()
{
    return $this->_catalogLayer;
}

/**
 * Retrieve loaded category collection
 *
 * @return AbstractCollection
 */
public function getLoadedProductCollection()
{
    return $this->_getProductCollection();
}

/**
 * Retrieve current view mode
 *
 * @return string
 */
public function getMode()
{
    if ($this->getChildBlock('toolbar')) {
        return $this->getChildBlock('toolbar')->getCurrentMode();
    }

    return $this->getDefaultListingMode();
}

/**
 * Get listing mode for products if toolbar is removed from layout.
 * Use the general configuration for product list mode from config path catalog/frontend/list_mode as default value
 * or mode data from block declaration from layout.
 *
 * @return string
 */
private function getDefaultListingMode()
{
    // default Toolbar when the toolbar layout is not used
    $defaultToolbar = $this->getToolbarBlock();
    $availableModes = $defaultToolbar->getModes();

    // layout config mode
    $mode = $this->getData('mode');

    if (!$mode || !isset($availableModes[$mode])) {
        // default config mode
        $mode = $defaultToolbar->getCurrentMode();
    }

    return $mode;
}

/**
 * Need use as _prepareLayout - but problem in declaring collection from
 * another block (was problem with search result)
 * @return $this
 */
protected function _beforeToHtml()
{
    $collection = $this->_getProductCollection();

    $this->addToolbarBlock($collection);

    $collection->load();

    return parent::_beforeToHtml();
}

/**
 * Add toolbar block from product listing layout
 *
 * @param Collection $collection
 */
private function addToolbarBlock(Collection $collection)
{
    $toolbarLayout = $this->getToolbarFromLayout();

    if ($toolbarLayout) {
        $this->configureToolbar($toolbarLayout, $collection);
    }
}

/**
 * Retrieve Toolbar block from layout or a default Toolbar
 *
 * @return Toolbar
 */
public function getToolbarBlock()
{
    $block = $this->getToolbarFromLayout();

    if (!$block) {
        $block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, uniqid(microtime()));
    }

    return $block;
}

/**
 * Get toolbar block from layout
 *
 * @return bool|Toolbar
 */
private function getToolbarFromLayout()
{
    $blockName = $this->getToolbarBlockName();

    $toolbarLayout = false;

    if ($blockName) {
        $toolbarLayout = $this->getLayout()->getBlock($blockName);
    }

    return $toolbarLayout;
}

/**
 * Retrieve additional blocks html
 *
 * @return string
 */
public function getAdditionalHtml()
{
    return $this->getChildHtml('additional');
}

/**
 * Retrieve list toolbar HTML
 *
 * @return string
 */
public function getToolbarHtml()
{
    return $this->getChildHtml('toolbar');
}

/**
 * @param AbstractCollection $collection
 * @return $this
 */
public function setCollection($collection)
{
    $this->_productCollection = $collection;
    return $this;
}

/**
 * @param array|string|integer| Element $code
 * @return $this
 */
public function addAttribute($code)
{
    $this->_getProductCollection()->addAttributeToSelect($code);
    return $this;
}

/**
 * @return mixed
 */
public function getPriceBlockTemplate()
{
    return $this->_getData('price_block_template');
}

/**
 * Retrieve Catalog Config object
 *
 * @return Config
 */
protected function _getConfig()
{
    return $this->_catalogConfig;
}

/**
 * Prepare Sort By fields from Category Data
 *
 * @param Category $category
 * @return $this
 */
public function prepareSortableFieldsByCategory($category)
{
    if (!$this->getAvailableOrders()) {
        $this->setAvailableOrders($category->getAvailableSortByOptions());
    }
    $availableOrders = $this->getAvailableOrders();
    if (!$this->getSortBy()) {
        $categorySortBy = $this->getDefaultSortBy() ?: $category->getDefaultSortBy();
        if ($categorySortBy) {
            if (!$availableOrders) {
                $availableOrders = $this->_getConfig()->getAttributeUsedForSortByArray();
            }
            if (isset($availableOrders[$categorySortBy])) {
                $this->setSortBy($categorySortBy);
            }
        }
    }

    return $this;
}

/**
 * Return identifiers for produced content
 *
 * @return array
 */
public function getIdentities()
{
    $identities = [];

    $category = $this->getLayer()->getCurrentCategory();
    if ($category) {
        $identities[] = Product::CACHE_PRODUCT_CATEGORY_TAG . '_' . $category->getId();
    }

    //Check if category page shows only static block (No products)
    if ($category->getData('display_mode') == Category::DM_PAGE) {
        return $identities;
    }

    foreach ($this->_getProductCollection() as $item) {
        $identities = array_merge($identities, $item->getIdentities());
    }

    return $identities;
}

/**
 * Get post parameters
 *
 * @param Product $product
 * @return array
 */
public function getAddToCartPostParams(Product $product)
{
    $url = $this->getAddToCartUrl($product);
    return [
        'action' => $url,
        'data' => [
            'product' => $product->getEntityId(),
            ActionInterface::PARAM_NAME_URL_ENCODED => $this->urlHelper->getEncodedUrl($url),
        ]
    ];
}

/**
 * @param Product $product
 * @return string
 */
public function getProductPrice(Product $product)
{
    $priceRender = $this->getPriceRender();

    $price = '';
    if ($priceRender) {
        $price = $priceRender->render(
            FinalPrice::PRICE_CODE,
            $product,
            [
                'include_container' => true,
                'display_minimal_price' => true,
                'zone' => Render::ZONE_ITEM_LIST,
                'list_category_page' => true
            ]
        );
    }

    return $price;
}

/**
 * Specifies that price rendering should be done for the list of products
 * i.e. rendering happens in the scope of product list, but not single product
 *
 * @return Render
 */
protected function getPriceRender()
{
    return $this->getLayout()->getBlock('product.price.render.default')
        ->setData('is_product_list', true);
}

/**
 * Configures product collection from a layer and returns its instance.
 *
 * Also in the scope of a product collection configuration, this method initiates configuration of Toolbar.
 * The reason to do this is because we have a bunch of legacy code
 * where Toolbar configures several options of a collection and therefore this block depends on the Toolbar.
 *
 * This dependency leads to a situation where Toolbar sometimes called to configure a product collection,
 * and sometimes not.
 *
 * To unify this behavior and prevent potential bugs this dependency is explicitly called
 * when product collection initialized.
 *
 * @return Collection
 */
private function initializeProductCollection()
{
    $layer = $this->getLayer();
    /* @var $layer Layer */
    if ($this->getShowRootCategory()) {
        $this->setCategoryId($this->_storeManager->getStore()->getRootCategoryId());
    }

    // if this is a product view page
    if ($this->_coreRegistry->registry('product')) {
        // get collection of categories this product is associated with
        $categories = $this->_coreRegistry->registry('product')
            ->getCategoryCollection()->setPage(1, 1)
            ->load();
        // if the product is associated with any category
        if ($categories->count()) {
            // show products from this category
            $this->setCategoryId(current($categories->getIterator())->getId());
        }
    }

    $origCategory = null;
    if ($this->getCategoryId()) {
        try {
            $category = $this->categoryRepository->get($this->getCategoryId());
        } catch (NoSuchEntityException $e) {
            $category = null;
        }

        if ($category) {
            $origCategory = $layer->getCurrentCategory();
            $layer->setCurrentCategory($category);
        }
    }
    $collection = $layer->getProductCollection();
    **Custom Code Starts From Here **
    $Customcollection = $layer->getProductCollection();
    $Customcollection->setOrder('price','ASC');


       $AllData = array();
       $newkey = array();


foreach ($Customcollection as $value) {
$number = $value->getModelNumber();
$year = $value->getModelYear();
$prdname  = $value->getName();
$newkey = $number.",".$year.",".$prdname;   
$AllData[$newkey][] = $value->getEntityID();
 }
      $AllKeys = array_keys($AllData);
  for($i=0; $i <count($AllData); $i++) { 
  $keysValue = $AllData[$AllKeys[$i]];
  $ValueCount = count($keysValue);
  if($ValueCount>1)
    {
        for ($j=0; $j<$ValueCount ; $j++) 
        {          
            if($j>0)
            {
               $collection->removeItemByKey($keysValue[$j]);
            }

        }
    }
   }
  **Custom Code Ends  Here **
    $this->prepareSortableFieldsByCategory($layer->getCurrentCategory());

    if ($origCategory) {
        $layer->setCurrentCategory($origCategory);
    }

    $this->addToolbarBlock($collection);

    $this->_eventManager->dispatch(
        'catalog_block_product_list_collection',
        ['collection' => $collection]
    );

    return $collection;
}

/**
 * Configures the Toolbar block with options from this block and configured product collection.
 *
 * The purpose of this method is the one-way sharing of different sorting related data
 * between this block, which is responsible for product list rendering,
 * and the Toolbar block, whose responsibility is a rendering of these options.
 *
 * @param ProductList\Toolbar $toolbar
 * @param Collection $collection
 * @return void
 */
private function configureToolbar(Toolbar $toolbar, Collection $collection)
{
    // use sortable parameters
    $orders = $this->getAvailableOrders();
    if ($orders) {
        $toolbar->setAvailableOrders($orders);
    }
    $sort = $this->getSortBy();
    if ($sort) {
        $toolbar->setDefaultOrder($sort);
    }
    $dir = $this->getDefaultDirection();
    if ($dir) {
        $toolbar->setDefaultDirection($dir);
    }
    $modes = $this->getModes();
    if ($modes) {
        $toolbar->setModes($modes);
    }
    // set collection to toolbar and apply sort
    $toolbar->setCollection($collection);
    $this->setChild('toolbar', $toolbar);
   }
   }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.