cancel
Showing results for 
Search instead for 
Did you mean: 

Magento 2.4.0 Sorting by custom eav attribute

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 vendor\Sorting\Setup\Patch\Data;

use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Framework\Setup\Patch\PatchRevertableInterface;
use Magento\Eav\Setup\EavSetupFactory;

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(
                \Magento\Catalog\Model\Product::ENTITY,
                $attribute,
                [
                    'type' => 'int',
                    'backend' => '',
                    'frontend' => '',
                    'label' => $attribute . ' - Attribute for sorting.',
                    'sort_order' => $attribute,
                    'input' => 'text',
                    'global'=> \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::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();
    }
    //rest of code
} 

 

 

namespace vendor\Sorting\Model\Indexer;


use Magento\Catalog\Model\Product\Action as ProductResourceAction;
use Magento\Framework\App\ResourceConnection;
use Magento\Catalog\Model\Indexer\Product\Category;

class SortingAttributes implements \Magento\Framework\Indexer\ActionInterface, \Magento\Framework\Mview\ActionInterface {

    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();
    }

}

1 REPLY 1

Re: Magento 2.4.0 Sorting by custom eav attribute


@michalrata5484 wrote:

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 vendor\Sorting\Setup\Patch\Data;

use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Framework\Setup\Patch\PatchRevertableInterface;
use Magento\Eav\Setup\EavSetupFactory;

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(
                \Magento\Catalog\Model\Product::ENTITY,
                $attribute,
                [
                    'type' => 'int',
                    'backend' => '',
                    'frontend' => '',
                    'label' => $attribute . ' - Attribute for sorting.',
                    'sort_order' => $attribute,
                    'input' => 'text',
                    'global'=> \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::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();
    }
    //rest of code
} 

 

RTasks Login

namespace vendor\Sorting\Model\Indexer;


use Magento\Catalog\Model\Product\Action as ProductResourceAction;
use Magento\Framework\App\ResourceConnection;
use Magento\Catalog\Model\Indexer\Product\Category;

class SortingAttributes implements \Magento\Framework\Indexer\ActionInterface, \Magento\Framework\Mview\ActionInterface {

    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();
    }

}


The sorting order may depend on the attribute type, the attribute option id, and the attribute value. If you are using an int type for your custom attributes, you may need to make sure that the option id and the value are consistent and sequential. For example, if you have an attribute called views, and you want to sort by ascending order, you may need to assign option id 1 to the value 0, option id 2 to the value 1, and so on.