Does anyone have an idea of how to validate function works on product attribute while creating custom condition rule !?
I'm stuck in validating condition rule
Here, in my scenario, I've to validate my order's SKU with custom rule's saved condition SKU.
Any Advice?
I've referred and tried to apply this solution but doesn't work for me Because in that case, she wants to fetch SKU from the cart (Quote) but in my case, I've to fetch SKU from ordered data that means sales_order_place_after. Maybe that doesn't make sense, I just have to understand that validate function with abstract model etc... The main thing is I'm stuck in that important concept of condition rule Any solution or explanation regarding this?
Here's my model code
Vendor\Module\Model\Rule\Condition\Customer.php
<?php
namespace Vendor\Module\Model\Rule\Condition;
class Customer extends \Magento\Rule\Model\Condition\Product\AbstractProduct
{
protected function _addSpecialAttributes(array &$attributes)
{
parent::_addSpecialAttributes($attributes);
$attributes['quote_item_qty'] = __('Quantity in cart');
$attributes['quote_item_price'] = __('Price in cart');
$attributes['quote_item_row_total'] = __('Row total in cart');
$attributes['parent::category_ids'] = __('Category (Parent only)');
$attributes['children::category_ids'] = __('Category (Children Only)');
}
public function getAttribute(): string
{
$attribute = $this->getData('attribute');
if (strpos($attribute, '::') !== false) {
list(, $attribute) = explode('::', $attribute);
}
return $attribute;
}
/**
* @inheritdoc
*/
public function getAttributeName()
{
$attribute = $this->getAttribute();
if ($this->getAttributeScope()) {
$attribute = $this->getAttributeScope() . '::' . $attribute;
}
return $this->getAttributeOption($attribute);
}
/**
* @inheritdoc
*/
public function loadAttributeOptions()
{
$productAttributes = $this->_productResource->loadAllAttributes()->getAttributesByCode();
$attributes = [];
foreach ($productAttributes as $attribute) {
/* @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
if (!$attribute->isAllowedForRuleCondition()
|| !$attribute->getDataUsingMethod($this->_isUsedForRuleProperty)
) {
continue;
}
$frontLabel = $attribute->getFrontendLabel();
$attributes[$attribute->getAttributeCode()] = $frontLabel;
$attributes['parent::' . $attribute->getAttributeCode()] = $frontLabel . __('(Parent Only)');
$attributes['children::' . $attribute->getAttributeCode()] = $frontLabel . __('(Children Only)');
}
$this->_addSpecialAttributes($attributes);
asort($attributes);
$this->setAttributeOption($attributes);
return $this;
}
/**
* @inheritdoc
*/
public function getAttributeElementHtml()
{
$html = parent::getAttributeElementHtml() .
$this->getAttributeScopeElement()->getHtml();
return $html;
}
private function getAttributeScopeElement(): \Magento\Framework\Data\Form\Element\AbstractElement
{
return $this->getForm()->addField(
$this->getPrefix() . '__' . $this->getId() . '__attribute_scope',
'hidden',
[
'name' => $this->elementName . '[' . $this->getPrefix() . '][' . $this->getId() . '][attribute_scope]',
'value' => $this->getAttributeScope(),
'no_span' => true,
'class' => 'hidden',
'data-form-part' => $this->getFormName(),
]
);
}
public function setAttribute(string $value)
{
if (strpos($value, '::') !== false) {
list($scope, $attribute) = explode('::', $value);
$this->setData('attribute_scope', $scope);
$this->setData('attribute', $attribute);
} else {
$this->setData('attribute', $value);
}
}
/**
* @inheritdoc
*/
public function loadArray($arr)
{
parent::loadArray($arr);
$this->setAttributeScope($arr['attribute_scope'] ?? null);
return $this;
}
/**
* @inheritdoc
*/
public function asArray(array $arrAttributes = [])
{
$out = parent::asArray($arrAttributes);
$out['attribute_scope'] = $this->getAttributeScope();
return $out;
}
Vendor\Module\Model\Rule\Condition\Combine.php
<?php
namespace Vendor\Module\Model\Rule\Condition;
use Magento\Catalog\Model\ResourceModel\Product\Collection;
class Combine extends \Magento\Rule\Model\Condition\Combine
{
protected $_ruleConditionProd;
public function __construct(
\Magento\Rule\Model\Condition\Context $context,
\Magento\SalesRule\Model\Rule\Condition\Product $ruleConditionProduct,
array $data = []
) {
parent::__construct($context, $data);
$this->_ruleConditionProd = $ruleConditionProduct;
$this->setType(\Magento\SalesRule\Model\Rule\Condition\Product\Combine::class);
}
public function getNewChildSelectOptions()
{
$productAttributes = $this->_ruleConditionProd->loadAttributeOptions()->getAttributeOption();
$pAttributes = [];
$iAttributes = [];
foreach ($productAttributes as $code => $label) {
if (strpos($code, 'quote_item_') === 0) {
$iAttributes[] = [
'value' => \Magento\SalesRule\Model\Rule\Condition\Product::class . '|' . $code,
'label' => $label,
];
} else {
$pAttributes[] = [
'value' => \Magento\SalesRule\Model\Rule\Condition\Product::class . '|' . $code,
'label' => $label,
];
}
}
$conditions = parent::getNewChildSelectOptions();
$conditions = array_merge_recursive(
$conditions,
[
[
'value' => \Magento\SalesRule\Model\Rule\Condition\Product\Combine::class,
'label' => __('Conditions Combination'),
],
['label' => __('Cart Item Attribute'), 'value' => $iAttributes],
['label' => __('Product Attribute'), 'value' => $pAttributes]
]
);
return $conditions;
}
/**
* Collect validated attributes
*
* @param Collection $productCollection
* @return $this
*/
public function collectValidatedAttributes($productCollection)
{
foreach ($this->getConditions() as $condition) {
$condition->collectValidatedAttributes($productCollection);
}
return $this;
}
/**
* @inheritdoc
* @since 101.0.6
*/
protected function _isValid($entity)
{
if (!$this->getConditions()) {
return true;
}
$all = $this->getAggregator() === 'all';
$true = (bool)$this->getValue();
foreach ($this->getConditions() as $cond) {
if ($entity instanceof \Magento\Framework\Model\AbstractModel) {
$validated = $this->validateEntity($cond, $entity);
} else {
$validated = $cond->validateByEntityId($entity);
}
if ($all && $validated !== $true) {
return false;
} elseif (!$all && $validated === $true) {
return true;
}
}
return $all ? true : false;
}
/**
* Validate entity.
*
* @param object $cond
* @param \Magento\Framework\Model\AbstractModel $entity
* @return bool
*/
private function validateEntity($cond, \Magento\Framework\Model\AbstractModel $entity)
{
$true = (bool)$this->getValue();
$validated = !$true;
foreach ($this->retrieveValidateEntities($cond->getAttributeScope(), $entity) as $validateEntity) {
$validated = $cond->validate($validateEntity);
if ($validated === $true) {
break;
}
}
return $validated;
}
private function retrieveValidateEntities($attributeScope, \Magento\Framework\Model\AbstractModel $entity)
{
if ($attributeScope === 'parent') {
$validateEntities = [$entity];
} elseif ($attributeScope === 'children') {
$validateEntities = $entity->getChildren() ?: [$entity];
} else {
$validateEntities = $entity->getChildren() ?: [];
$validateEntities[] = $entity;
}
return $validateEntities;
}
}
Vendor\Module\Model\Rule.php
<?php
namespace Vendor\Module\Model;
use Magento\Quote\Model\Quote\Address;
use Magento\Rule\Model\AbstractModel;
use Magento\Framework\ObjectManagerInterface;
class Rule extends AbstractModel
{
protected $_eventPrefix = 'vendor_module';
protected $_eventObject = 'rule';
protected $objectManager;
protected $condCombineFactory;
protected $condProdCombineF;
protected $validatedAddresses = [];
public function __construct(
\Magento\Framework\Model\Context $context,
ObjectManagerInterface $objectManager,
\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->objectManager = $objectManager;
$this->condCombineFactory = $condCombineFactory;
$this->condProdCombineF = $condProdCombineF;
parent::__construct($context, $registry, $formFactory, $localeDate, $resource, $resourceCollection, $data);
}
protected function _construct()
{
parent::_construct();
$this->_init('Vendor\Module\Model\ResourceModel\Rule');
$this->setIdFieldName('rule_id');
}
public function getConditionsInstance()
{
return $this->objectManager->create('Vendor\Module\Model\Rule\Condition\Combine');
}
public function getActionsInstance()
{
return $this->objectManager->create('Magento\SalesRule\Model\Rule\Condition\Product\Combine');
}
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;
}
}
Vendor\Module\Model\Validator.php
<?php
namespace Vendor\Module\Model;
use Magento\Framework\DataObject;
use Magento\Framework\ObjectManagerInterface;
use Magento\Framework\App\State;
class Validator extends DataObject
{
protected $rateAdjustments = [];
protected $objectManager;
private $appState;
public function __construct(ObjectManagerInterface $objectManager, State $appState, array $data = [])
{
$this->objectManager = $objectManager;
$this->appState = $appState;
parent::__construct($data);
}
public function init($request)
{
$this->setRequest($request);
return $this;
}
My Updated code... in if condition I'm checking whether the flag variable is true or false but it stops the execution from validate the condition $ruleConditionData prints my rule data also
Array ( [rule_id] => 1 [name] => update4 [is_active] => 1 [stores] => 2 [customer_groups] => 0 [conditions_serialized] => {"type":"Magento\SalesRule\Model\Rule\Condition\Product\Combine","attribute":null,"operator":null,"value":"1","is_value_processed":null,"aggregator":"all","conditions":[{"type":"Magento\SalesRule\Model\Rule\Condition\Product","attribute":"sku","operator":"==","value":"similar more","is_value_processed":false,"attribute_scope":""}]} )
public function execute(Observer $observer)
{
$flag = false;
if ($this->helper->isEnabled()) {
$orderIds = $observer->getOrderIds();
$order = $this->orderFactory->create()->load($orderIds[0]);
foreach ($order->getAllItems() as $orderItem) {
$itemSku = $orderItem->getSku();
$ruleId = 1;
$prdData = $this->productloader->create()->loadByAttribute("sku", $itemSku );
$ruleConditionData = $this->ruleFactory->create()->load($ruleId);
print_r($ruleConditionData->getData());
if ($ruleConditionData->getConditions()->validate($prdData)) {
$flag = true;
}
}
}