Skip to content

Magento 2.4.0 Sorting by custom eav attribute

I have a index that adds eav values ​​to products and it adds the correct values, these eav attributes are used to sort the product catalog, but this sorting is not correct, it started with a value of 0 or 1 (if I change the sorting direction), example when is ascending, first products are who have values 0 and on bottom are products who have value 1, but products with higher values ​​are found middle directory instead sort direction. When all of this values has been changed to random number, and reindex, and once again changed but to normal value, and reindex then work prefect.


namespace vendorSortingSetupPatchData;

use MagentoFrameworkSetupModuleDataSetupInterface;
use MagentoFrameworkSetupPatchDataPatchInterface;
use MagentoFrameworkSetupPatchPatchRevertableInterface;
use MagentoEavSetupEavSetupFactory;

class SortEAV implements DataPatchInterface, PatchRevertableInterface
{

    private const SortAttributes = ["views", "soldcount"];

    /**
     * @var ModuleDataSetupInterface
     */
    private $moduleDataSetup;

    /**
     * @var EavSetupFactory
     */
    private $EavSetupFactory;

    /**
     * @param ModuleDataSetupInterface $moduleDataSetup
     * @param EavSetupFactory $EavSetupFactory
     */
    public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        EavSetupFactory $EavSetupFactory
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->EavSetupFactory = $EavSetupFactory;
    }

    /**
     * @inheritdoc
     */
    public function apply()
    {
        $this->moduleDataSetup->getConnection()->startSetup();
        $EavSetup = $this->EavSetupFactory->create(["setup" => $this->moduleDataSetup]);
        foreach (self::SortAttributes as $attribute) {
            $EavSetup->addAttribute(
                MagentoCatalogModelProduct::ENTITY,
                $attribute,
                [
                    'type' => 'int',
                    'backend' => '',
                    'frontend' => '',
                    'label' => $attribute . ' - Attribute for sorting.',
                    'sort_order' => $attribute,
                    'input' => 'text',
                    'global'=> MagentoEavModelEntityAttributeScopedAttributeInterface::SCOPE_GLOBAL,
                    'visible' => true,
                    'required' => false,
                    'user_defined' => false,
                    'default' => '1000',
                    'searchable' => false,
                    'used_in_product_listing' => true,
                    'filterable' => true,
                    'comparable' => true,
                    'visible_on_front' => true,
                    'used_for_sort_by' => true,
                    'unique' => false,
                    'apply_to' => ''
                ]
            );
        }

        $this->moduleDataSetup->getConnection()->endSetup();
    }

    /**
     * @inheritdoc
     */
    public static function getDependencies(): array
    {
        return [];
    }

    public function revert()
    {
        $this->moduleDataSetup->getConnection()->startSetup();
        $EavSetup = $this->EavSetupFactory->create(["setup" => $this->moduleDataSetup]);
        foreach (self::SortAttributes as $attribute) {
            $EavSetup->removeAttribute(
                MagentoCatalogModelProduct::ENTITY,
                $attribute
            );
        }
        $this->moduleDataSetup->getConnection()->endSetup();
    }

    /**
     * @inheritdoc
     */
    public function getAliases(): array
    {
        return [];
    }

}

<?php

namespace vendorSortingModelIndexer;


use MagentoCatalogModelProductAction as ProductResourceAction;
use MagentoFrameworkAppResourceConnection;
use MagentoCatalogModelIndexerProductCategory;

class SortingAttributes implements MagentoFrameworkIndexerActionInterface, MagentoFrameworkMviewActionInterface {

    const LimitPage = 400;

    /**
     * @var ProductResourceAction
     */
    protected $action;

    /**
     * @var ResourceConnection
     */
    protected $resource;

    /**
     * @var AdapterInterface
     */
    protected  $connection;


    /**
     * Index constructor
     * @param ProductResourceAction $action
     * @param ResourceConnection $resource
     */
    public function __construct(
        ProductResourceAction $action,
        ResourceConnection $resource
    )
    {
        $this->action = $action;
        $this->resource = $resource;
    }

    /**
     * @return AdapterInterface
     */
    protected function GetDatabaseConnection(): AdapterInterface
    {
        if (!isset($this->connection))
            $this->connection = $this->resource->getConnection();
        return $this->connection;
    }

    public function execute($ids){
        $this->executeFull();
    }

    /**
     * @throws Zend_Db_Select_Exception
     * @throws Exception
     */
    public function executeFull(){

        $con = $this->GetDatabaseConnection();
        $data = $con->select()->from(
            ["Product" => $this->resource->getTableName("catalog_product_entity")],
            ["entity_id"]
        );

        $page = 1;
        do {
            $data->limitPage($page, self::LimitPage);
            $items = $con->fetchAll($data);
            foreach ($items as $row) {
                $this->action->updateAttributes(
                    [$row["entity_id"]],
                    [
                        'soldcount' => 0,
                        'views' => 0
                    ],
                    0
                );
            }
            $page++;
        } while(!empty($items));
        $data = $con->select()->union([
            $con->select()->from(
                ["Sales" => $this->resource->getTableName("sales_order_item")],
                [
                    "product_id" => "product_id",
                    "count" => "sum(qty_ordered)",
                    "store_id" => "store_id",
                    "source" => new Zend_Db_Expr("'sales'")
                ]
            )->join(
                ["Product" => $this->resource->getTableName("catalog_product_entity")],
                "Product.entity_id = Sales.product_id"
            )->group(["Sales.product_id", "Sales.store_id"]),
            $con->select()->from(
                ["Views" => $this->resource->getTableName("report_viewed_product_index")],
                [
                    "product_id" => "product_id",
                    "count" => "count(Views.product_id)",
                    "store_id" => "store_id",
                    "source" => new Zend_Db_Expr("'views'")
                ]
            )->join(
                ["Product" => $this->resource->getTableName("catalog_product_entity")],
                "Product.entity_id = Views.product_id"
            )->group(["Views.product_id", "Views.store_id"])
        ]);

        $page = 1;
        do {
            $data->limitPage($page, self::LimitPage);
            $items = $con->fetchAll($data);
            foreach ($items as $row) {

                if ($row["source"] === 'views') {
                    $this->action->updateAttributes(
                        [$row["product_id"]],
                        ['views' => (int)$row["count"]],
                        0
                    );
                }

                if ($row["source"] === 'sales') {
                    $this->action->updateAttributes(
                        [$row["product_id"]],
                        ['soldcount' => (int)$row["count"]],
                        0
                    );
                }
            }
            $page++;
        } while(!empty($items));
    }

    public function executeList(array $ids){
        $this->executeFull();
    }

    public function executeRow($id){
        $this->executeFull();
    }

}