Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rendering a custom collection with smile his layered navigation #3013

Closed
Minirock opened this issue Jul 26, 2023 · 3 comments
Closed

Rendering a custom collection with smile his layered navigation #3013

Minirock opened this issue Jul 26, 2023 · 3 comments
Assignees
Labels

Comments

@Minirock
Copy link

Environment :

    "smile/elasticsuite": "~2.10.13" 
    magento 2.4.3

Do you guys have a working full example of how to load a custom collection in frontend using smile ?

I already can do the job going to a virtual category url and adding my filter parameters in the url as magento works there is no issue with that but i would like to be able to achieve the same result by directly altering the collection without any parameters in the url.

If i analyse it the error make sense as addSortFilterParameters is only defined in smille and not in the magento 2 collection. But i can't really understand why it's not using the smile fulltext collection directly.

I have lots of code so i could provide it but if someone have a working solution I wouldn't say no ;)

I have been trying something but end up facing a wall with this error

Error: Call to undefined method Magento\Catalog\Model\ResourceModel\Product\Collection\Interceptor::addSortFilterParameters() in /var/www/magento/vendor/smile/elasticsuite/src/module-elasticsuite-catalog/Plugin/LayerPlugin.php:87
Stack trace:
#0 /var/www/magento/vendor/smile/elasticsuite/src/module-elasticsuite-catalog/Plugin/LayerPlugin.php(67): Smile\ElasticsuiteCatalog\Plugin\LayerPlugin->setSortParams()
#1 /var/www/magento/vendor/magento/framework/Interception/Interceptor.php(121): Smile\ElasticsuiteCatalog\Plugin\LayerPlugin->beforePrepareProductCollection()
#2 /var/www/magento/vendor/magento/framework/Interception/Interceptor.php(153): Sa\CustomCollection\Model\Layer\Interceptor->Magento\Framework\Interception{closure}()
#3 /var/www/magento/generated/code/Sa/CustomCollection/Model/Layer/Interceptor.php(41): Sa\CustomCollection\Model\Layer\Interceptor->___callPlugins()
#4 /var/www/magento/vendor/magento/module-catalog/Model/Layer.php(147): Sa\CustomCollection\Model\Layer\Interceptor->prepareProductCollection()
#5 /var/www/magento/app/code/Sa/CustomCollection/Model/Layer.php(9): Magento\Catalog\Model\Layer->getProductCollection()
#6 /var/www/magento/generated/code/Sa/CustomCollection/Model/Layer/Interceptor.php(23): Sa\CustomCollection\Model\Layer->getProductCollection()
#7 /var/www/magento/vendor/magento/module-catalog/Block/Product/ListProduct.php(481): Sa\CustomCollection\Model\Layer\Interceptor->getProductCollection()
#8 /var/www/magento/vendor/magento/module-catalog/Block/Product/ListProduct.php(121): Magento\Catalog\Block\Product\ListProduct->initializeProductCollection()
#9 /var/www/magento/vendor/magento/module-catalog/Block/Product/ListProduct.php(200): Magento\Catalog\Block\Product\ListProduct->_getProductCollection()
#10 /var/www/magento/vendor/magento/framework/View/Element/AbstractBlock.php(1113): Magento\Catalog\Block\Product\ListProduct->_beforeToHtml()
#11 /var/www/magento/vendor/magento/framework/View/Element/AbstractBlock.php(1118): Magento\Framework\View\Element\AbstractBlock->Magento\Framework\View\Element{closure}()
#12 /var/www/magento/vendor/magento/framework/View/Element/AbstractBlock.php(678): Magento\Framework\View\Element\AbstractBlock->_loadCache()
#13 /var/www/magento/generated/code/Sa/CustomCollection/Block/Product/ListProduct/Interceptor.php(617): Magento\Framework\View\Element\AbstractBlock->toHtml()
#14 /var/www/magento/vendor/magento/framework/View/Layout.php(578): Sa\CustomCollection\Block\Product\ListProduct\Interceptor->toHtml()
#15 /var/www/magento/vendor/magento/framework/View/Layout.php(555): Magento\Framework\View\Layout->_renderBlock()
#16 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(149): Magento\Framework\View\Layout->renderNonCachedElement()
#17 /var/www/magento/vendor/magento/framework/View/Layout.php(510): Magento\Framework\View\Layout\Interceptor->renderNonCachedElement()
#18 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(140): Magento\Framework\View\Layout->renderElement()
#19 /var/www/magento/vendor/magento/framework/View/Layout.php(606): Magento\Framework\View\Layout\Interceptor->renderElement()
#20 /var/www/magento/vendor/magento/framework/View/Layout.php(557): Magento\Framework\View\Layout->_renderContainer()
#21 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(149): Magento\Framework\View\Layout->renderNonCachedElement()
#22 /var/www/magento/vendor/magento/framework/View/Layout.php(510): Magento\Framework\View\Layout\Interceptor->renderNonCachedElement()
#23 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(140): Magento\Framework\View\Layout->renderElement()
#24 /var/www/magento/vendor/magento/framework/View/Layout.php(606): Magento\Framework\View\Layout\Interceptor->renderElement()
#25 /var/www/magento/vendor/magento/framework/View/Layout.php(557): Magento\Framework\View\Layout->_renderContainer()
#26 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(149): Magento\Framework\View\Layout->renderNonCachedElement()
#27 /var/www/magento/vendor/magento/framework/View/Layout.php(510): Magento\Framework\View\Layout\Interceptor->renderNonCachedElement()
#28 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(140): Magento\Framework\View\Layout->renderElement()
#29 /var/www/magento/vendor/magento/framework/View/Layout.php(606): Magento\Framework\View\Layout\Interceptor->renderElement()
#30 /var/www/magento/vendor/magento/framework/View/Layout.php(557): Magento\Framework\View\Layout->_renderContainer()
#31 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(149): Magento\Framework\View\Layout->renderNonCachedElement()
#32 /var/www/magento/vendor/magento/framework/View/Layout.php(510): Magento\Framework\View\Layout\Interceptor->renderNonCachedElement()
#33 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(140): Magento\Framework\View\Layout->renderElement()
#34 /var/www/magento/vendor/magento/framework/View/Layout.php(606): Magento\Framework\View\Layout\Interceptor->renderElement()
#35 /var/www/magento/vendor/magento/framework/View/Layout.php(557): Magento\Framework\View\Layout->_renderContainer()
#36 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(149): Magento\Framework\View\Layout->renderNonCachedElement()
#37 /var/www/magento/vendor/magento/framework/View/Layout.php(510): Magento\Framework\View\Layout\Interceptor->renderNonCachedElement()
#38 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(140): Magento\Framework\View\Layout->renderElement()
#39 /var/www/magento/vendor/magento/framework/View/Layout.php(606): Magento\Framework\View\Layout\Interceptor->renderElement()
#40 /var/www/magento/vendor/magento/framework/View/Layout.php(557): Magento\Framework\View\Layout->_renderContainer()
#41 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(149): Magento\Framework\View\Layout->renderNonCachedElement()
#42 /var/www/magento/vendor/magento/framework/View/Layout.php(510): Magento\Framework\View\Layout\Interceptor->renderNonCachedElement()
#43 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(140): Magento\Framework\View\Layout->renderElement()
#44 /var/www/magento/vendor/magento/framework/View/Layout.php(606): Magento\Framework\View\Layout\Interceptor->renderElement()
#45 /var/www/magento/vendor/magento/framework/View/Layout.php(557): Magento\Framework\View\Layout->_renderContainer()
#46 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(149): Magento\Framework\View\Layout->renderNonCachedElement()
#47 /var/www/magento/vendor/magento/framework/View/Layout.php(510): Magento\Framework\View\Layout\Interceptor->renderNonCachedElement()
#48 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(140): Magento\Framework\View\Layout->renderElement()
#49 /var/www/magento/vendor/magento/framework/View/Layout.php(975): Magento\Framework\View\Layout\Interceptor->renderElement()
#50 /var/www/magento/vendor/magento/framework/Interception/Interceptor.php(58): Magento\Framework\View\Layout->getOutput()
#51 /var/www/magento/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Framework\View\Layout\Interceptor->___callParent()
#52 /var/www/magento/vendor/magento/framework/Interception/Interceptor.php(153): Magento\Framework\View\Layout\Interceptor->Magento\Framework\Interception{closure}()
#53 /var/www/magento/generated/code/Magento/Framework/View/Layout/Interceptor.php(347): Magento\Framework\View\Layout\Interceptor->___callPlugins()
#54 /var/www/magento/vendor/magento/framework/View/Result/Page.php(260): Magento\Framework\View\Layout\Interceptor->getOutput()
#55 /var/www/magento/vendor/magento/framework/View/Result/Layout.php(171): Magento\Framework\View\Result\Page->render()
#56 /var/www/magento/vendor/magento/framework/Interception/Interceptor.php(58): Magento\Framework\View\Result\Layout->renderResult()
#57 /var/www/magento/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Framework\View\Result\Page\Interceptor->___callParent()
#58 /var/www/magento/vendor/magento/framework/Interception/Interceptor.php(153): Magento\Framework\View\Result\Page\Interceptor->Magento\Framework\Interception{closure}()
#59 /var/www/magento/generated/code/Magento/Framework/View/Result/Page/Interceptor.php(95): Magento\Framework\View\Result\Page\Interceptor->___callPlugins()
#60 /var/www/magento/vendor/magento/framework/App/Http.php(120): Magento\Framework\View\Result\Page\Interceptor->renderResult()
#61 /var/www/magento/generated/code/Magento/Framework/App/Http/Interceptor.php(23): Magento\Framework\App\Http->launch()
#62 /var/www/magento/vendor/magento/framework/App/Bootstrap.php(264): Magento\Framework\App\Http\Interceptor->launch()
#63 /var/www/magento/pub/index.php(29): Magento\Framework\App\Bootstrap->run()
#64 {main}

@romainruaud
Copy link
Collaborator

@Minirock did you try something like this ?

$collection = $this->_categoryLayerFactory
    ->create()
    ->setCurrentCategory($category)
    ->getProductCollection();

Or

// $collectionFactory must be a Magento\CatalogSearch\Model\ResourceModel\Fulltext\CollectionFactory

$collection = $layer->prepareProductCollection($collectionFactory->create())

@Minirock
Copy link
Author

Minirock commented Aug 2, 2023

@romainruaud @vahonc

Hi thanks for your reply, this was actually our first shot and totally changed our approach in the meantime. Now we managed to get almost what we want.

We have a custom route testplate/index/index

When we enter that url we managed to have a pre filtered collection, the sorting and filter seems to work so as the toolbar and the product count.
The only issue is with the left filters items who doesn't adjust them to the pre filtered collection, they act like if we were printing all products, what we are not doing obviously.

So lets enter more in details of the code we made, i've been creating a custom Block. You will see in our Block that we filter on a field libelle which makes that this url will give us our filtered collection items printed properly http://sa.dev-aims.fr/testplate/index/index

But with the issue on the filter considering the whole products mentionned above.

Now if i enter any filter in the url http://sa.dev-aims.fr/testplate/index/index/?tws_piece_marque_veh=OPEL

Then everything is fine, i have my filter taking the libelle from the pre filtering and the brand being filtered from the url...and i guess when we have a filter in the url there is a treatment done in the layer that i'm not doing when i have no parameter in the url to filter...which makes the filter applied wrong on the first loading of the page.

<?php

namespace Sa\CustomCollection\Block;
use Magento\Catalog\Api\CategoryRepositoryInterface;
use Magento\Catalog\Block\Product\ListProduct;
use Magento\Catalog\Helper\Output as OutputHelper;
use Magento\Catalog\Model\Layer\Resolver;
use Magento\Framework\Data\Helper\PostHelper;
use Magento\Framework\Url\Helper\Data;
use Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext\CollectionFactory as ElasticCollectionFactory;

class Collection extends ListProduct
{
    /**
     * @var ElasticCollectionFactory
     */
    protected $elasticCollectionFactory;

    public function __construct(\Magento\Catalog\Block\Product\Context $context, PostHelper $postDataHelper,
                                Resolver $layerResolver, CategoryRepositoryInterface $categoryRepository,
                                ElasticCollectionFactory $elasticCollectionFactory,
                                Data $urlHelper, array $data = [], ?OutputHelper $outputHelper = null)
    {
        $this->elasticCollectionFactory = $elasticCollectionFactory;
        parent::__construct($context, $postDataHelper, $layerResolver, $categoryRepository, $urlHelper, $data, $outputHelper);
    }


    /**
     * Retrieve the filtered product collection
     *
     * @return \Magento\Catalog\Model\ResourceModel\Product\Collection
     */
    public function getFilteredProductCollection()
    {


        // Get the ElasticSuite product collection
        $productCollection = $this->elasticCollectionFactory->create()
            ->addFieldToSelect('name')
            ->addFieldToSelect('sku')
            ->addFieldToSelect('small_image')
            ->addFieldToSelect('price')
            ->addFieldToSelect('tws_piece_libelle')
            ->addFieldToSelect('tws_piece_marque_veh')
            ->addFieldToSelect('tws_piece_modele_veh')
            ->addFieldToSelect('tws_piece_annee_veh')
            ->addFieldToFilter('tws_piece_libelle', ['eq' =>'TRAPPE A CARBURANT'])
            ->setCurPage(1)
            ->setPageSize(12);

        $dir = "ASC";
        $attributeToSort = 'position';

        foreach ($this->getRequest()->getParams() as $name => $value){
            if($name != "product_list_order" && $name != "product_list_dir"){
                $productCollection->addFieldToFilter($name,['eq' => $value]);
            }else{
                if($name == "product_list_dir"){
                    $dir = "DESC";
                }
                if($name == "product_list_order"){
                    $attributeToSort = $value;
                }
            }
        }
        $productCollection->addAttributeToSort($attributeToSort,$dir);

        $this->getToolbarBlock()->setCollection($productCollection);
        $this->getLayer()->prepareProductCollection($productCollection);

        return $productCollection;
    }
}

And here is our layout

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <attribute name="class" value="spa-cat" />

        <referenceContainer name="sidebar.main">
            <block class="Magento\LayeredNavigation\Block\Navigation\Category" name="catalog.leftnav" template="Smile_ElasticsuiteCatalog::layer/view.phtml">
                <block class="Magento\LayeredNavigation\Block\Navigation\State" name="catalog.navigation.state" as="state" />
                <block class="Smile\ElasticsuiteCatalog\Block\Navigation\FilterRenderer" name="catalog.navigation.renderer" as="renderer">
                    <block class="Smile\ElasticsuiteCatalog\Block\Navigation\Renderer\Attribute" name="catalogsearch.navigation.renderer.attribute" template="Smile_ElasticsuiteCatalog::layer/filter/attribute.phtml" after="-" />
                    <block class="Smile\ElasticsuiteCatalog\Block\Navigation\Renderer\Category" name="catalogsearch.navigation.renderer.category" template="Smile_ElasticsuiteCatalog::layer/filter/default.phtml" />
                    <block class="Smile\ElasticsuiteCatalog\Block\Navigation\Renderer\Slider" name="catalog.navigation.renderer.slider" template="Smile_ElasticsuiteCatalog::layer/filter/slider.phtml" />
                    <block class="Smile\ElasticsuiteCatalog\Block\Navigation\Renderer\PriceSlider" name="catalog.navigation.renderer.price.slider" template="Smile_ElasticsuiteCatalog::layer/filter/slider.phtml" />
                </block>
            </block>
        </referenceContainer>

        <referenceContainer name="content">
            <block class="Sa\CustomCollection\Block\Collection" name="testplate_index_index" template="Sa_CustomCollection::product_list.phtml">
                <container name="category.product.list.additional" as="additional" />
                <block class="Magento\Framework\View\Element\RendererList" name="category.product.type.details.renderers" as="details.renderers">
                    <block class="Magento\Framework\View\Element\Template" name="category.product.type.details.renderers.default" as="default" />
                </block>
                <block class="Magento\Catalog\Block\Product\ProductList\Toolbar" name="product_list_toolbar" template="Magento_Catalog::product/list/toolbar.phtml">
                    <block class="Magento\Theme\Block\Html\Pager" name="product_list_toolbar_pager" />
                </block>
                <action method="setToolbarBlockName">
                    <argument name="name" xsi:type="string">product_list_toolbar</argument>
                </action>
            </block>
        </referenceContainer>

        <block class="Magento\Framework\View\Element\Template" name="spa-cat-alert" template="Magento_Catalog::category/alertes.phtml" />
        <block class="Magento\Framework\View\Element\Template" name="spa-cat-reas" template="Magento_Cms::home/spa-reas.phtml" />

        <move element="spa-cat-alert" destination="content.bottom" before="-" />
        <move element="spa-cat-reas" destination="page.bottom" before="-" />

    </body>
</page>

And in the template we have this

<?php
/**
 * @var Sa\CustomCollection\Block\Collection $block
 * @var Smile\ElasticsuiteCatalog\Model\ResourceModel\Product\Fulltext\Collection $_productCollection
 * @var Magento\Framework\Escaper $escaper
 * @var Magento\Catalog\Helper\Output $_helper
 * @var Aims\Catalog\Helper\Data $helperStock
 * @var Aims\Tax\Helper\ProductPrice $customerHelper
 */

$_helper = $block->getData('outputHelper');
$helperStock = $this->helper('Aims\Catalog\Helper\Data');
$customerHelper = $this->helper('Aims\Tax\Helper\ProductPrice');

$_productCollection = $block->getFilteredProductCollection();

$groupCode = $customerHelper->getCustomerGroupCode();
$tax = true;
if (!in_array($groupCode, $customerHelper->getGroupTtc())) {
    $tax = false;
}

$minPrice = '';

?>

<?php if (!$_productCollection->count()) { ?>
    <div class="message info empty">
        <div><?= $escaper->escapeHtml(__('We can\'t find products matching the selection.')); ?></div>
    </div>
<?php } else { ?>
    <?= $block->getToolbarHtml(); ?>
    <?= $block->getAdditionalHtml(); ?>

    <div class="products wrapper grid products-grid">
        <ol class="spa-product-list">
            <?php foreach ($_productCollection as $_product) {
                $attributeSetName = $helperStock->getAttributeSetName($_product->getAttributeSetId());
                if ($attributeSetName === 'Default') {
                    $sku = $_product->getSku();
                    $libelle = $_product->getData('tws_piece_libelle');
                    $qty = $helperStock->getCountSimilarPiece($sku, $libelle);
                    if ($qty > 0) {
                        $minPrice = $helperStock->getMinimalPrice($sku, $libelle, $tax);
                    }
                    $productImage = $block->getImage($_product, 'category_page_grid');
                } ?>
                <li class="spa-product-item">
                    <div class="spa-product-box">
                        <a href="<?= $escaper->escapeUrl($_product->getProductUrl()); ?>" class="spa-product-link"></a>
                        <span class="spa-product-img"><?= $productImage->toHtml(); ?></span>
                        <h2 class="spa-product-name"><?= $_helper->productAttribute($_product, $_product->getName(), 'name'); ?></h2>

                        <!-- Stocks -->
                        <?php if ($attributeSetName === 'Default') { ?>
                            <?php if ($qty > 0) { ?>
                                <span class="spa-product-stock">
                                    <?= __('%1 en stock', $qty); ?>
                                </span>
                            <?php } else { ?>
                                <span class="spa-product-stock out">
                                    <?= __('Hors stock'); ?>
                                </span>
                            <?php } ?>
                        <?php } ?>

                        <!-- Modèle -->
                        <span class="spa-product-modele">
                            <?php $marque = $_product->getData('tws_piece_marque_veh'); ?>
                            <?php $modele = $_product->getData('tws_piece_modele_veh'); ?>
                            <?php $annee = $_product->getData('tws_piece_annee_veh'); ?>
                            <span><?= $marque . ' ' . $modele . ' ' . $annee; ?></span>
                        </span>

                        <!-- Prix -->
                        <?php if ($attributeSetName === 'Default' && $qty > 1 && $minPrice !== '') { ?>
                            <span class="spa-product-price">
                                <?php
                                $priceType = $helperStock->getPriceType();
                                $price = $this->helper('Magento\Framework\Pricing\Helper\Data')->currency($minPrice, true, false);
                                $price_explode = explode(',', $price);
                                $price_format = "<span class='price-bold'>" . $price_explode[0] . "</span><span>," . $price_explode[1] ." ". $priceType."</span>";
                                ?>
                                <span class="from"><?= __('à partir de'); ?></span>
                                <span class="price"><?= $price_format; ?></span>
                            </span>
                        <?php } else { ?>
                            <span class="spa-product-price">
                                <?= $block->getProductPrice($_product); ?>
                            </span>
                        <?php } ?>

                        <span class="spa-btn"><?= __('Découvrir'); ?></span>
                    </div>
                </li>
            <?php } ?>
            <li class="spa-product-item spa-product-item-empty"></li>
            <li class="spa-product-item spa-product-item-empty"></li>
        </ol>
    </div>

    <?= $block->getChildBlock('toolbar')->setIsBottom(true)->toHtml(); ?>
<?php } ?>

@romainruaud
Copy link
Collaborator

Hi @Minirock

this is too specific for being answered here as part of the Open Source maintenance of Elasticsuite.

I move this into a discussion so that maybe someone from the community will be able to help you.

If you want more help directly from the Elasticsuite core team, that's something we can provide as paid support to your customer. If you are interested, contact us by mail at [email protected]

regards

@Smile-SA Smile-SA locked and limited conversation to collaborators Aug 2, 2023
@romainruaud romainruaud converted this issue into discussion #3018 Aug 2, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
Projects
None yet
Development

No branches or pull requests

3 participants