4

how to get matching products based on rule conditions i need to filter product grid according to rule condition in my custom module I have used it as a filter

enter image description here

Array
(
    [conditions] => Array
        (
            [1] => Array
                (
                    [type] => Magento\CatalogRule\Model\Rule\Condition\Combine
                    [aggregator] => all
                    [value] => 1
                    [new_child] => 
                )

            [1--1] => Array
                (
                    [type] => Magento\CatalogRule\Model\Rule\Condition\Product
                    [attribute] => attribute_set_id
                    [operator] => ==
                    [value] => 15
                )

            [1--2] => Array
                (
                    [type] => Magento\CatalogRule\Model\Rule\Condition\Product
                    [attribute] => price
                    [operator] => <
                    [value] => 2000
                )

        )

)

I have this array of rule conditions and I need products based on conditions

2 Answers 2

10

finally I found the solution.

/*Controller code */

    $modelRule = $this->_objectManager->create('NameSpace\ModuleName\Model\Rule');
                $data = $this->prepareData($data);
                $modelRule->loadPost($data);
    $productIds = $modelRule->getListProductIds();


    protected function prepareData($data)
        {
            if (isset($data['rule']['conditions'])) {
                $data['conditions'] = $data['rule']['conditions'];
            }
            unset($data['rule']);
            return $data;
        }

NameSpace\ModuleName\Model\Rule.php

    namespace NameSpace\ModuleName\Model;

    class Rule extends \Magento\CatalogRule\Model\Rule {
        /**
         * Prefix of model events names
         *
         * @var string
         */
        protected $_eventPrefix = 'catalogrule_rule';

        /**
         * Parameter name in event
         *
         * In observe method you can use $observer->getEvent()->getRule() in this case
         *
         * @var string
         */
        protected $_eventObject = 'rule';

        /**
         * Store matched product Ids
         *
         * @var array
         */
        protected $_productIds;

        /**
         * Limitation for products collection
         *
         * @var int|array|null
         */
        protected $_productsFilter = null;

        /**
         * Store current date at "Y-m-d H:i:s" format
         *
         * @var string
         */
        protected $_now;

        /**
         * Cached data of prices calculated by price rules
         *
         * @var array
         */
        protected static $_priceRulesData = [];

        /**
         * Catalog rule data
         *
         * @var \Magento\CatalogRule\Helper\Data
         */
        protected $_catalogRuleData;

        /**
         * @var \Magento\Framework\App\Cache\TypeListInterface
         */
        protected $_cacheTypesList;

        /**
         * @var array
         */
        protected $_relatedCacheTypes;

        /**
         * @var \Magento\Framework\Stdlib\DateTime
         */
        protected $dateTime;

        /**
         * @var \Magento\Framework\Model\ResourceModel\Iterator
         */
        protected $_resourceIterator;

        /**
         * @var \Magento\Customer\Model\Session
         */
        protected $_customerSession;

        /**
         * @var \Magento\CatalogRule\Model\Rule\Condition\CombineFactory
         */
        protected $_combineFactory;

        /**
         * @var \Magento\CatalogRule\Model\Rule\Action\CollectionFactory
         */
        protected $_actionCollectionFactory;

        /**
         * @var \Magento\Catalog\Model\ProductFactory
         */
        protected $_productFactory;

        /**
         * @var \Magento\Store\Model\StoreManagerInterface
         */
        protected $_storeManager;

        /**
         * @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory
         */
        protected $_productCollectionFactory;

        /**
         * @var \Magento\CatalogRule\Model\Indexer\Rule\RuleProductProcessor;
         */
        protected $_ruleProductProcessor;

        /**
         * @var Data\Condition\Converter
         */
        protected $ruleConditionConverter;

        /**
         * Rule constructor.
         * @param \Magento\Framework\Model\Context $context
         * @param \Magento\Framework\Registry $registry
         * @param \Magento\Framework\Data\FormFactory $formFactory
         * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
         * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory
         * @param \Magento\Store\Model\StoreManagerInterface $storeManager
         * @param Rule\Condition\CombineFactory $combineFactory
         * @param Rule\Action\CollectionFactory $actionCollectionFactory
         * @param \Magento\Catalog\Model\ProductFactory $productFactory
         * @param \Magento\Framework\Model\ResourceModel\Iterator $resourceIterator
         * @param \Magento\Customer\Model\Session $customerSession
         * @param \Magento\CatalogRule\Helper\Data $catalogRuleData
         * @param \Magento\Framework\App\Cache\TypeListInterface $cacheTypesList
         * @param \Magento\Framework\Stdlib\DateTime $dateTime
         * @param Indexer\Rule\RuleProductProcessor $ruleProductProcessor
         * @param \Magento\Framework\Model\ResourceModel\AbstractResource|null $resource
         * @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection
         * @param array $relatedCacheTypes
         * @param array $data
         *
         * @SuppressWarnings(PHPMD.ExcessiveParameterList)
         */

        public function __construct(
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Data\FormFactory $formFactory,
        \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
        \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\CatalogRule\Model\Rule\Condition\CombineFactory $combineFactory,
        \Magento\CatalogRule\Model\Rule\Action\CollectionFactory $actionCollectionFactory,
        \Magento\Catalog\Model\ProductFactory $productFactory,
        \Magento\Framework\Model\ResourceModel\Iterator $resourceIterator,
        \Magento\Customer\Model\Session $customerSession,
        \Magento\CatalogRule\Helper\Data $catalogRuleData,
        \Magento\Framework\App\Cache\TypeListInterface $cacheTypesList,
        \Magento\Framework\Stdlib\DateTime $dateTime,
        \Magento\CatalogRule\Model\Indexer\Rule\RuleProductProcessor $ruleProductProcessor,
        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
        \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
        array $relatedCacheTypes = [],
        array $data = []
        ) {

            parent::__construct(
                    $context,
                    $registry,
                    $formFactory,
                    $localeDate,
                    $productCollectionFactory,
                    $storeManager,
                    $combineFactory,
                    $actionCollectionFactory,
                    $productFactory,
                    $resourceIterator,
                    $customerSession,
                    $catalogRuleData,
                    $cacheTypesList,
                    $dateTime,
                    $ruleProductProcessor,
                    $resource,
                    $resourceCollection,
                    $relatedCacheTypes,
                    $data
            );
        }
        /**
         * Init resource model and id field
         *
         * @return void
         */
        protected function _construct()
        {
            parent::_construct();
            $this->_init('Magento\CatalogRule\Model\ResourceModel\Rule');
            $this->setIdFieldName('rule_id');
        }
        /**
         * Getter for rule conditions collection
         *
         * @return \Magento\Rule\Model\Condition\Combine
         */
        public function getConditionsInstance()
        {
            return $this->_combineFactory->create();
        }

        /**
         * Getter for rule actions collection
         *
         * @return \Magento\CatalogRule\Model\Rule\Action\Collection
         */
        public function getActionsInstance()
        {
            return $this->_actionCollectionFactory->create();
        }

        public function toArray(array $arrAttributes = array()) {
        return parent::toArray($arrAttributes);
        }

        public function getListProductIds()
        {    
         $productCollection = \Magento\Framework\App\ObjectManager::getInstance()->create(
             '\Magento\Catalog\Model\ResourceModel\Product\Collection'
         );
         $productFactory = \Magento\Framework\App\ObjectManager::getInstance()->create(
             '\Magento\Catalog\Model\ProductFactory'
         );
         $this->_productIds = [];
         $this->setCollectedAttributes([]);
         $this->getConditions()->collectValidatedAttributes($productCollection);
         \Magento\Framework\App\ObjectManager::getInstance()->create(
             '\Magento\Framework\Model\ResourceModel\Iterator'
         )->walk(
             $productCollection->getSelect(),
             [[$this, 'callbackValidateProduct']],
             [
                 'attributes' => $this->getCollectedAttributes(),
                 'product' => $productFactory->create()
             ]
         );
        return $this->_productIds;
        }
        /**
        * Callback function for product matching
        *
        * @param array $args
        * @return void
        */
        public function callbackValidateProduct($args)
        {
         $product = clone $args['product'];
         $product->setData($args['row']);
         $websites = $this->_getWebsitesMap();
         foreach ($websites as $websiteId => $defaultStoreId) {
             $product->setStoreId($defaultStoreId);
             if ($this->getConditions()->validate($product)) {
                 $this->_productIds[] = $product->getId();
             }
         }
        }
        /**
        * Prepare website map
        *
        * @return array
        */
        protected function _getWebsitesMap()
        {
         $map = [];
         $websites = \Magento\Framework\App\ObjectManager::getInstance()->create(
             '\Magento\Store\Model\StoreManagerInterface'
         )->getWebsites();
         foreach ($websites as $website) {
             // Continue if website has no store to be able to create catalog rule for website without store
             if ($website->getDefaultStore() === null) {
                 continue;
             }
             $map[$website->getId()] = $website->getDefaultStore()->getId();
         }
         return $map;
        }

    }
0

Method-1 by using getConditions()->validate()

  protected $customConditionModel;
    protected $productFactory;
 
    public function __construct(
        ....................................................
        \Magento\Catalog\Model\ProductFactory $productFactory,
        \VendoreName\AddConditionFiled\Model\CustomConditionFactory $customConditionModel,
        ....................................................
    ) {
        ....................................................
        $this->productFactory = $productFactory;
        $this->customConditionModel = $customConditionModel;
        ....................................................
    }
 
    public function checkCondition()
    {
        echo "<pre>";
        $prdId = 6; //bag product id
        // Get product data by id
        $prdData = $this->productFactory->create()->load($prdId);
        // get rule collection
        $ruleColl = $this->customConditionModel->create()->getCollection();
        foreach ($ruleColl as $ruleKey => $ruleVal) {
            // check Product with condition
            if ($ruleVal->getConditions()->validate($prdData)) {
                echo "Rule Id " . $ruleVal->getId() . " Match<br/>";
            }
        }
    }

Method-2 by using the Model function getMatchProductIds() which we already created.

protected $customConditionModel;

public function __construct(
    ....................................................
    \VendoreName\AddConditionFiled\Model\CustomConditionFactory $customConditionModel,
    ....................................................
) {
    ....................................................
    $this->customConditionModel = $customConditionModel;
    ....................................................

}

public function checkCondition()
{
    echo "<pre>";
    // get rule collection
    $ruleColl = $this->customConditionModel->create()->getCollection();
    foreach ($ruleColl as $ruleKey => $ruleVal) {
        // get all product's Ids with match with rule
        echo "***** Rule Id " . $ruleVal->getId() . " Match Product Ids ***** <br/>";
        $matchIds = array_values(array_unique($ruleVal->getMatchProductIds()));
        print_r($matchIds);
    }
}

Model file give below:

<?php

namespace VendoreName\AddConditionFiled\Model;

use VendoreName\AddConditionFiled\Model\ResourceModel\CustomCondition as CustomConditionResourceModel;
use Magento\Quote\Model\Quote\Address;
use Magento\Rule\Model\AbstractModel;

class CustomCondition extends AbstractModel
{
    protected $_eventPrefix = 'VendoreName_addconditionfiled';
    protected $_eventObject = 'rule';
    protected $condCombineFactory;
    protected $condProdCombineF;
    protected $validatedAddresses = [];
    protected $_selectProductIds;
    protected $_displayProductIds;

    public function __construct(
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Data\FormFactory $formFactory,
        \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
        \Magento\CatalogRule\Model\Rule\Condition\CombineFactory $condCombineFactory,
        \Magento\SalesRule\Model\Rule\Condition\Product\CombineFactory $condProdCombineF,
        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
        \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
        array $data = []
    ) {
        $this->condCombineFactory = $condCombineFactory;
        $this->condProdCombineF = $condProdCombineF;
        parent::__construct($context, $registry, $formFactory, $localeDate, $resource, $resourceCollection, $data);
    }

    protected function _construct()
    {
        parent::_construct();
        $this->_init(CustomConditionResourceModel::class);
        $this->setIdFieldName('rule_id');
    }

    public function getConditionsInstance()
    {
        return $this->condCombineFactory->create();
    }

    public function getActionsInstance()
    {
        return $this->condCombineFactory->create();
    }

    public function hasIsValidForAddress($address)
    {
        $addressId = $this->_getAddressId($address);
        return isset($this->validatedAddresses[$addressId]) ? true : false;
    }

    public function setIsValidForAddress($address, $validationResult)
    {
        $addressId = $this->_getAddressId($address);
        $this->validatedAddresses[$addressId] = $validationResult;
        return $this;
    }

    public function getIsValidForAddress($address)
    {
        $addressId = $this->_getAddressId($address);
        return isset($this->validatedAddresses[$addressId]) ? $this->validatedAddresses[$addressId] : false;
    }

    private function _getAddressId($address)
    {
        if ($address instanceof Address) {
            return $address->getId();
        }
        return $address;
    }

    public function getConditionsFieldSetId($formName = '')
    {
        return $formName . 'rule_conditions_fieldset_' . $this->getId();
    }

    public function getActionFieldSetId($formName = '')
    {
        return $formName . 'rule_actions_fieldset_' . $this->getId();
    }

    public function getMatchProductIds()
    {
        $productCollection = \Magento\Framework\App\ObjectManager::getInstance()->create(
            '\Magento\Catalog\Model\ResourceModel\Product\Collection'
        );
        $productFactory = \Magento\Framework\App\ObjectManager::getInstance()->create(
            '\Magento\Catalog\Model\ProductFactory'
        );
        $this->_selectProductIds = [];
        $this->setCollectedAttributes([]);
        $this->getConditions()->collectValidatedAttributes($productCollection);
        \Magento\Framework\App\ObjectManager::getInstance()->create(
            '\Magento\Framework\Model\ResourceModel\Iterator'
        )->walk(
            $productCollection->getSelect(),
            [[$this, 'callbackValidateProductCondition']],
            [
                'attributes' => $this->getCollectedAttributes(),
                'product' => $productFactory->create(),
            ]
        );
        return $this->_selectProductIds;
    }

    public function callbackValidateProductCondition($args)
    {
        $product = clone $args['product'];
        $product->setData($args['row']);
        $websites = $this->_getWebsitesMap();
        foreach ($websites as $websiteId => $defaultStoreId) {
            $product->setStoreId($defaultStoreId);
            if ($this->getConditions()->validate($product)) {
                $this->_selectProductIds[] = $product->getId();
            }
        }
    }

    protected function _getWebsitesMap()
    {
        $map = [];
        $websites = \Magento\Framework\App\ObjectManager::getInstance()->create(
            '\Magento\Store\Model\StoreManagerInterface'
        )->getWebsites();
        foreach ($websites as $website) {
            if ($website->getDefaultStore() === null) {
                continue;
            }
            $map[$website->getId()] = $website->getDefaultStore()->getId();
        }
        return $map;
    }
}

Check Full Example click Here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.