3

How to validate a condition rules based on product attribute in magento 2

backend:

enter image description here

code:

    $product_id = '3';  // Crown Summit Backpack sku is 24-MB03
    $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
    $rules = $objectManager->create('Vendor\Module\Model\Rule')->getCollection();
    foreach ($rules as $rule) {
        $product = $objectManager->get('Magento\Catalog\Model\Product')->load($product_id);
        $item = $objectManager->create('Magento\Catalog\Model\Product');
        $item->setProduct($product);
        $validate = $rule->getActions()->validate($item);
    }
    var_dump($validate);
    var_dump($product);

Expected result is false but it always shows true. validation not done properly on product attributes.

var_dump($validate);

enter image description here

var_dump($product);

enter image description here

Vendor\Module\Model\Rule.php

<?php
namespace Vendor\Module\Model;
use Magento\Quote\Model\Quote\Address;
use Magento\Rule\Model\AbstractModel;
/**
 * Class Rule
 * @package Vendor\Module\Model
 *
 * @method int|null getRuleId()
 * @method Rule setRuleId(int $id)
 */
class Rule extends AbstractModel
{
    /**
     * Prefix of model events names
     *
     * @var string
     */
    protected $_eventPrefix = 'vendor_module';
    /**
     * Parameter name in event
     *
     * In observe method you can use $observer->getEvent()->getRule() in this case
     *
     * @var string
     */
    protected $_eventObject = 'rule';
    /** @var \Magento\SalesRule\Model\Rule\Condition\CombineFactory */
    protected $condCombineFactory;
    /** @var \Magento\SalesRule\Model\Rule\Condition\Product\CombineFactory */
    protected $condProdCombineF;
    /**
     * Store already validated addresses and validation results
     *
     * @var array
     */
    protected $validatedAddresses = [];
    /**
     * @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\SalesRule\Model\Rule\Condition\CombineFactory $condCombineFactory
     * @param \Magento\SalesRule\Model\Rule\Condition\Product\CombineFactory $condProdCombineF
     * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
     * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
     * @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\SalesRule\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);
    }
    /**
     * Set resource model and Id field name
     *
     * @return void
     */
    protected function _construct()
    {
        parent::_construct();
        $this->_init('Vendor\Module\Model\ResourceModel\Rule');
        $this->setIdFieldName('rule_id');
    }
    /**
     * Get rule condition combine model instance
     *
     * @return \Magento\SalesRule\Model\Rule\Condition\Combine
     */
      public function getConditionsInstance()
    {
        return $this->condCombineFactory->create();
    }

    /**
     * Get rule condition product combine model instance
     *
     * @return \Magento\SalesRule\Model\Rule\Condition\Product\Combine
     */
    public function getActionsInstance()
    {
        return $this->condProdCombineF->create();
    }
    /**
     * Check cached validation result for specific address
     *
     * @param Address $address
     * @return bool
     */
    public function hasIsValidForAddress($address)
    {
        $addressId = $this->_getAddressId($address);
        return isset($this->validatedAddresses[$addressId]) ? true : false;
    }
    /**
     * Set validation result for specific address to results cache
     *
     * @param Address $address
     * @param bool $validationResult
     * @return $this
     */
    public function setIsValidForAddress($address, $validationResult)
    {
        $addressId = $this->_getAddressId($address);
        $this->validatedAddresses[$addressId] = $validationResult;
        return $this;
    }
    /**
     * Get cached validation result for specific address
     *
     * @param Address $address
     * @return bool
     * @SuppressWarnings(PHPMD.BooleanGetMethodName)
     */
    public function getIsValidForAddress($address)
    {
        $addressId = $this->_getAddressId($address);
        return isset($this->validatedAddresses[$addressId]) ? $this->validatedAddresses[$addressId] : false;
    }
    /**
     * Return id for address
     *
     * @param Address $address
     * @return string
     */
    private function _getAddressId($address)
    {
        if ($address instanceof Address) {
            return $address->getId();
        }
        return $address;
    }
}

Finally i done it, here my updated code

public function execute()
    {  
      $validate  = array();
      $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
      $quoteId = $this->cart->getQuote()->getId();
      $quote =  $this->quoteFactory->load($quoteId);
      $fakeQuote = clone $quote;
      $fakeQuote->setId(null);
       $items = $this->cart->getQuote()->getAllItems();
       $rules = $objectManager->create('Vendor\Module\Model\Rule')->getCollection();
      foreach ($rules as $rule){
          foreach($items as $item){
            $productId = $item->getProductId();
            $product = $objectManager->create('Magento\Catalog\Model\Product')->load($productId);
            $quoteItem = $objectManager->create('Magento\Quote\Model\Quote\Item');
            $quoteItem->setQuote($fakeQuote)->setProduct($product);
            $quoteItem->setAllItems(array($product));
            $quoteItem->getProduct()->setProductId($product->getEntityId());
            $validate = $rule->getConditions()->validate($quoteItem);
        } 
    }
   // var_dump($validate); 
    return $validate;
    }
7
  • You need to check with all the cart items? – Ranganathan Dec 13 '19 at 6:43
  • yes, i need to check with all cart item – Divya Sekar Dec 13 '19 at 6:44
  • Did you tried here with cart items? I think the issue is because you are sending product object instead of cart item object. – Ranganathan Dec 13 '19 at 6:45
  • first of all i tried static product object its not validate properly – Divya Sekar Dec 13 '19 at 6:51
  • I don't know about these...My assumption is you have to send cart item object...Let me try this with my env – Ranganathan Dec 13 '19 at 6:52
2

Seems like you validating your model (product) using the actions, but logically you should use the conditions, like:

$rule->getConditions()->validate($item);

Here is full code with changes:

$product_id = '3';  // Crown Summit Backpack sku is 24-MB03
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$rules = $objectManager->create('Vendor\Module\Model\Rule')->getCollection();
foreach ($rules as $rule) {
    $product = $objectManager->get('Magento\Catalog\Model\Product')->load($product_id);
    $item = $objectManager->create('Magento\Catalog\Model\Product');
    $item->setProduct($product);
    $validate = $rule->getConditions()->validate($item);
}
var_dump($validate);
var_dump($product);

I think the getActions() is a conditions for the Apply the rule to (see the select below your main block) or other conditions in your model.

You can detect what you are using for validation pretty simple, just print out the $rule->getConditions()->asStringRecursive() and $rule->getActions()->asStringRecursive(). You must see which method returns desired conditions.

PS: the $rule->getActions()->validate($item); always returns true because empty conditions always means the any item is valid.

10
  • i used $rule->getConditions()->validate($item) but it reflects a error like Warning: Invalid argument supplied for foreach() in D:\wamp64\www\m2\magento\vendor\magento\module-sales-rule\Model\Rule\Condition\Product\Found.php on line 65 – Divya Sekar Dec 12 '19 at 12:44
  • 2
    @divyasekar It mean that you have error somewhere in your model. The line 65 is foreach ($model->getAllItems() as $item) { so it try to work with you wrapper-model as with a Quote, but you set the Product. Try this: $item = $objectManager->create('Magento\Quote\Model\Quote'); then add item to quote and try to validate using quote. – Siarhey Uchukhlebau Dec 12 '19 at 12:49
  • i cant get you clearly , what i m understand of your suggestion is try with quote item instead of product if i m wright – Divya Sekar Dec 12 '19 at 14:08
  • 1
    @divyasekar Sorry, my english is not good enough :) Yes, you should try with a Quote object in which your product must be set as an quote item (you can use the addItem method). I will try to cover this issue more broadly in our blog article in future. – Siarhey Uchukhlebau Dec 12 '19 at 14:22
  • Thanks @Siarhey Uchukhlebau i was done it by your suggestion – Divya Sekar Dec 13 '19 at 10:51
1

Finally i done it, here my updated code

public function execute()
    {  
      $validate  = array();
      $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
      $quoteId = $this->cart->getQuote()->getId();
      $quote =  $this->quoteFactory->load($quoteId);
      $fakeQuote = clone $quote;
      $fakeQuote->setId(null);
       $items = $this->cart->getQuote()->getAllItems();
       $rules = $objectManager->create('Vendor\Module\Model\Rule')->getCollection();
      foreach ($rules as $rule){
          foreach($items as $item){
            $productId = $item->getProductId();
            $product = $objectManager->create('Magento\Catalog\Model\Product')->load($productId);
            $quoteItem = $objectManager->create('Magento\Quote\Model\Quote\Item');
            $quoteItem->setQuote($fakeQuote)->setProduct($product);
            $quoteItem->setAllItems(array($product));
            $quoteItem->getProduct()->setProductId($product->getEntityId());
            $validate = $rule->getConditions()->validate($quoteItem);
        } 
    }
   // var_dump($validate); 
    return $validate;
    }
0

Try with cart items using below code

$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$cart = $objectManager->get('\Magento\Checkout\Model\Cart');
$items = $cart->getQuote()->getAllItems();

$rules = $objectManager->create('Vendor\Module\Model\Rule')->getCollection();

foreach($items as $item) {
    $validate = $rule->getActions()->validate($item);
}
var_dump($validate);
var_dump($product);            
7
  • @divyasekar can you please update Vendor\Module\Model\Rule class code? – Ranganathan Dec 13 '19 at 7:14
  • i update my code in the post – Divya Sekar Dec 13 '19 at 7:53
  • You are getting rules by getCollection but in Siarhey Uchukhlebau previous answer he is getting using getRules – Ranganathan Dec 13 '19 at 8:55
  • i also used a getting rules by getRules but the validation not done properly – Divya Sekar Dec 13 '19 at 9:48
  • ok let me check – Ranganathan Dec 13 '19 at 9:56

Your Answer

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

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