Magento 2 Edit Catalog Rule conditions in UI Form
-
01-03-2021 - |
Question
I have created a UI form with field catalog rule conditions. The form loads display the conditions section and it is saved in the table. But in edit case the conditions are not displayed.
Reference: https://www.mageworx.com/blog/2016/09/magento-2-module-with-conditions-model-fieldset/
Please help me to resolve this. Here is my code
Installschema.php
public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
{
$installer = $setup;
$contextInterface = $context;
$installer->startSetup();
$table = $installer->getConnection()->newTable(
$installer->getTable('example_label')
)->addColumn(
'label_id',
\Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
null,
['identity' => true, 'nullable' => false, 'primary' => true],
'ID'
)->addColumn(
'name',
\Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
255,
['nullable' => false],
'Name'
)->addColumn(
'conditions_serialized',
Table::TYPE_TEXT,
'4G',
[],
'Conditions Serialized'
)->addIndex(
$installer->getIdxName('example_label', ['name']),
['name']
)->setComment('example_label Table');
$installer->getConnection()->createTable($table);
}
UI Form
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="provider" xsi:type="string">productlabel_form.productlabel_form_data_source</item>
<item name="deps" xsi:type="string">productlabel_form.productlabel_form_data_source</item>
</item>
<item name="label" xsi:type="string" translate="true">Information</item>
<item name="config" xsi:type="array">
<item name="dataScope" xsi:type="string">data</item>
<item name="namespace" xsi:type="string">productlabel_form</item>
</item>
<item name="buttons" xsi:type="array">
<item name="save" xsi:type="string">Vendor\ProductLabel\Block\Adminhtml\Productlabel\Edit\Button\Save</item>
</item>
</argument>
<settings>
<layout>
<navContainerName>left</navContainerName>
<type>tabs</type>
</layout>
<deps>
<dep>productlabel_form.productlabel_form_data_source</dep>
</deps>
</settings>
<dataSource name="productlabel_form_data_source">
<argument name="dataProvider" xsi:type="configurableObject">
<argument name="class" xsi:type="string">Vendor\ProductLabel\Model\ResourceModel\Productlabel\DataProvider</argument>
<argument name="name" xsi:type="string">productlabel_form_data_source</argument>
<argument name="primaryFieldName" xsi:type="string">label_id</argument>
<argument name="requestFieldName" xsi:type="string">label_id</argument>
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="submit_url" xsi:type="url" path="productlabel/productlabel/save"/>
</item>
</argument>
</argument>
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="component" xsi:type="string">Magento_Ui/js/form/provider</item>
</item>
</argument>
</dataSource>
<fieldset name="productlabel_details">
<settings>
<label translate="true">Details</label>
</settings>
<field name="label_id">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="visible" xsi:type="boolean">false</item>
<item name="dataType" xsi:type="string">text</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">label_id</item>
</item>
</argument>
</field>
<field name="name">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">text</item>
<item name="label" xsi:type="string" translate="true">Name</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">name</item>
<item name="dataScope" xsi:type="string">name</item>
<item name="required" xsi:type="boolean">true</item>
<item name="validation" xsi:type="array">
<item name="required-entry" xsi:type="boolean">true</item>
</item>
</item>
</argument>
</field>
</fieldset>
<fieldset name="conditions_fieldset">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string" translate="true">Conditions</item>
<item name="collapsible" xsi:type="boolean">false</item>
</item>
</argument>
<container name="conditions_serialized_container" >
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="sortOrder" xsi:type="number">10</item>
</item>
</argument>
<htmlContent name="html_content">
<argument name="block" xsi:type="object">Vendor\ProductLabel\Block\Adminhtml\Productlabel\Edit\Tab\Conditions</argument>
</htmlContent>
</container>
</fieldset>
</form>
Conditions.php
use Magento\Framework\App\ObjectManager;
class Conditions extends \Magento\Backend\Block\Widget\Form\Generic
{
protected $_rendererFieldset;
protected $_conditions;
protected $_nameInLayout = 'conditions';
private $ruleFactory;
private $labelFactory;
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Data\FormFactory $formFactory,
\Magento\Rule\Block\Conditions $conditions,
\Magento\Backend\Block\Widget\Form\Renderer\Fieldset $rendererFieldset,
\Vendor\ProductLabel\Model\ProductlabelFactory $labelFactory,
array $data = []
) {
$this->_rendererFieldset = $rendererFieldset;
$this->_conditions = $conditions;
$this->labelFactory = $labelFactory;
parent::__construct($context, $registry, $formFactory, $data);
}
private function getRuleFactory()
{
if ($this->ruleFactory === null) {
$this->ruleFactory = ObjectManager::getInstance()->get('Magento\CatalogRule\Model\RuleFactory');
}
return $this->ruleFactory;
}
public function getTabClass()
{
return null;
}
public function getTabUrl()
{
return null;
}
public function isAjaxLoaded()
{
return false;
}
public function getTabLabel()
{
return __('Conditions');
}
public function getTabTitle()
{
return __('Conditions');
}
public function canShowTab()
{
return true;
}
public function isHidden()
{
return false;
}
protected function _prepareForm()
{
$model = $this->_coreRegistry->registry('current_label');
$form = $this->addTabToForm($model);
$this->setForm($form);
return parent::_prepareForm();
}
protected function addTabToForm($model, $fieldsetId = 'conditions_serialized_field', $formName = 'productlabel_form')
{
if (!$model) {
$id = $this->getRequest()->getParam('id');
$model = $this->getRuleFactory()->create();
$model->load($id);
}
$conditionsFieldSetId = $model->getConditionsFieldSetId($formName);
$newChildUrl = $this->getUrl(
'catalog_rule/promo_catalog/newConditionHtml/form/' . $conditionsFieldSetId,
['form_namespace' => $formName]
);
/** @var \Magento\Framework\Data\Form $form */
$form = $this->_formFactory->create();
$form->setHtmlIdPrefix('rule_');
$renderer = $this->_rendererFieldset->setTemplate(
'Magento_CatalogRule::promo/fieldset.phtml'
)->setNewChildUrl(
$newChildUrl
);
$fieldset = $form->addFieldset(
$fieldsetId,
[
'legend' => __(
'Apply the rule only if the following conditions are met (leave blank for all products).'
)
]
)->setRenderer(
$renderer
);
$fieldset->addField(
'conditions',
'text',
[
'name' => 'conditions',
'label' => __('Conditions'),
'title' => __('Conditions'),
'required' => true,
'data-form-part' => $formName
]
)->setRule(
$model
)->setRenderer(
$this->_conditions
);
$form->setValues($model->getData());
$this->setConditionFormName($model->getConditions(), $formName);
return $form;
}
private function setConditionFormName(\Magento\Rule\Model\Condition\AbstractCondition $conditions, $formName)
{
$conditions->setFormName($formName);
if ($conditions->getConditions() && is_array($conditions->getConditions())) {
foreach ($conditions->getConditions() as $condition) {
$this->setConditionFormName($condition, $formName);
}
}
Save Controller
public function execute()
{
$resultRedirect = $this->resultRedirectFactory->create();
$data = $this->getRequest()->getPostValue();
if ($data) {
if(isset($data['rule'])){
$dataArray['conditions_serialized'] = $this->serializer->serialize($data['rule']['conditions']);
}
$dataArray['name'] = $data['productlabel_details']['name'];
$label = $this->labelDataFactory->create();
$this->dataObjectHelper->populateWithArray(
$label,
$dataArray,
'\Vendor\ProductLabel\Api\Data\ProductlabelInterface'
);
try {
$labelInterface = $this->labelRepository->save($label);
$this->_getSession()->setFormData(false);
$this->messageManager->addSuccess(__('You saved the item.'));
return $resultRedirect->setPath('*/*/');
} catch (\Exception $e) {
}
}
return $resultRedirect->setPath('*/*/');
}
Edit Controller
public function execute()
{
$id = $this->getRequest()->getParam('label_id');
$model = $this->labelFactory->create();
if ($id) {
$model->load($id);
if (!$model->getId()) {
$resultRedirect = $this->resultRedirectFactory->create();
return $resultRedirect->setPath('*/*/');
}
}
$data = $this->_session->getPageData(true);
if (!empty($data)) {
$model->addData($data);
}
$model->getConditions()->setJsFormObject('conditions_serialized_field');
$this->coreRegistry->register('current_label', $model);
$resultPage = $this->resultPageFactory->create();
$this->initPage($resultPage)->addBreadcrumb(
$id ? __('Edit Product Label') : __('New Label'),
$id ? __('Edit Product Label') : __('New Label')
);
$resultPage->getConfig()->getTitle()->prepend(__(' labels'));
$resultPage->getConfig()->getTitle()->prepend($id? ('Edit Label') : __('New Label'));
return $resultPage;
}
Solution 2
I have fixed the issue by changing the save function.
Conditions Block
use Magento\Backend\Block\Widget\Tab\TabInterface;
use Magento\Backend\Block\Widget\Form\Generic;
class Conditions extends Generic implements TabInterface
{
protected $rendererFieldset;
protected $conditions;
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Data\FormFactory $formFactory,
\Magento\Rule\Block\Conditions $conditions,
\Magento\Backend\Block\Widget\Form\Renderer\Fieldset $rendererFieldset,
\Vendor\ProductLabel\Model\ProductlabelFactory $labelFactory,
array $data = []
) {
$this->rendererFieldset = $rendererFieldset;
$this->conditions = $conditions;
$this->labelFactory = $labelFactory;
parent::__construct($context, $registry, $formFactory, $data);
}
public function getTabLabel()
{
return __('Conditions');
}
public function getTabTitle()
{
return __('Conditions');
}
public function canShowTab()
{
return true;
}
public function isHidden()
{
return false;
}
protected function _prepareForm()
{
$model = $this->_coreRegistry->registry('current_label');
$form = $this->addTabToForm($model);
$this->setForm($form);
return parent::_prepareForm();
}
protected function addTabToForm($model, $fieldsetId = 'conditions_fieldset', $formName = 'productlabel_form')
{
if (!$model) {
$id = $this->getRequest()->getParam('id');
$model = $this->labelFactory->create();
$model->load($id);
}
$newChildUrl = $this->getUrl('productlabel/productlabel/newConditionHtml/form/rule_conditions_fieldset');
/** @var \Magento\Framework\Data\Form $form */
$form = $this->_formFactory->create();
$form->setHtmlIdPrefix('rule_');
$renderer = $this->rendererFieldset->setTemplate(
'Magento_CatalogRule::promo/fieldset.phtml'
)->setNewChildUrl(
$newChildUrl
);
$fieldset = $form->addFieldset(
$fieldsetId,
[
'legend' => __(
'Apply the rule only if the following conditions are met (leave blank for all products).'
)
]
)->setRenderer(
$renderer
);
$fieldset->addField(
'conditions',
'text',
[
'name' => 'conditions',
'label' => __('Conditions'),
'title' => __('Conditions'),
'required' => true,
'data-form-part' => $formName
]
)->setRule(
$model
)->setRenderer(
$this->conditions
);
$form->setValues($model->getData());
$this->setConditionFormName($model->getConditions(), $formName);
return $form;
}
private function setConditionFormName(\Magento\Rule\Model\Condition\AbstractCondition $conditions, $formName)
{
$conditions->setFormName($formName);
if ($conditions->getConditions() && is_array($conditions->getConditions())) {
foreach ($conditions->getConditions() as $condition) {
$this->setConditionFormName($condition, $formName);
}
}
}
}
NewConditionHtml Controller
namespace Vendor\ProductLabel\Controller\Adminhtml\Productlabel;
class NewConditionHtml extends \Vendor\ProductLabel\Controller\Adminhtml\Productlabel
{
public function execute()
{
$id = $this->getRequest()->getParam('id');
$labelFactory = $this->_objectManager->create('Vendor\ProductLabel\Model\ProductlabelFactory');
$typeArr = explode('|', str_replace('-', '/', $this->getRequest()->getParam('type')));
$type = $typeArr[0];
$model = $this->_objectManager->create(
$type
)->setId(
$id
)->setType(
$type
)->setRule(
$labelFactory->create()
)->setPrefix(
'conditions'
);
if (!empty($typeArr[1])) {
$model->setAttribute($typeArr[1]);
}
if ($model instanceof \Magento\Rule\Model\Condition\AbstractCondition) {
$model->setFormName('productlabel_form')->setJsFormObject('conditions_fieldset');
$html = $model->asHtmlRecursive();
} else {
$html = '';
}
$this->getResponse()->setBody($html);
}
}
Save Controller
class Save extends \Vendor\ProductLabel\Controller\Adminhtml\Productlabel
{
private $productModel;
private $labelFactory;
protected $imageUploader;
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Framework\Registry $registry,
\Vendor\ProductLabel\Model\ProductlabelFactory $labelFactory,
\Magento\Catalog\Model\Product $product
) {
$this->labelFactory = $labelFactory;
$this->productModel = $product;
parent::__construct($context, $registry);
}
public function execute()
{
$resultRedirect = $this->resultRedirectFactory->create();
$data = $this->getRequest()->getPostValue();
if ($data) {
$model = $this->labelFactory->create();
if(isset($data['productlabel_details']['label_id'])){
$id = $data['productlabel_details']['label_id'];
if ($id) {
$model->load($id);
$dataArray['id'] = $id;
}
}
if(isset($data['rule'])){
unset($data['rule']['conditions']['type']);
unset($data['rule']['conditions']['value']);
unset($data['rule']['conditions']['aggregator']);
$dataArray['conditions'] = $data['rule']['conditions'];//$this->serializer->serialize
}
$dataArray['form_key'] = $data['form_key'];
$dataArray['name'] = $data['productlabel_details']['name'];
$model->loadPost($dataArray);
try {
$model->save();
$this->_getSession()->setFormData(false);
$this->messageManager->addSuccess(__('You saved the item.'));
if ($this->getRequest()->getParam('back')) {
return $resultRedirect->setPath('*/*/edit', ['label_id' => $model->getId()]);
}
return $resultRedirect->setPath('*/*/');
} catch (\Exception $e) {
$this->messageManager->addError($e->getMessage());
$this->_getSession()->setFormData($data);
return $resultRedirect->setPath(
'*/*/edit',
['label_id' => $model->getId()]
);
}
}
return $resultRedirect->setPath('*/*/');
}
}
OTHER TIPS
Try with below way :
In your data provider file set condition field value like below.
Vendor\ProductLabel\Model\ResourceModel\Productlabel\DataProvider
"conditions_serialized_field" => $collectionData->getData('conditions_serialized_field')
I hope it works!
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange