Question

I'm working in Magento 2.2.5.

Basically, I have created a custom product attribute serilized_data with text as backend_type by using below file and want to save custom options of product in this attribute by serializing it.

app\code\Vendor\Module\Setup\InstallData.php

<?php

namespace Vendor\Module\Setup;

use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Catalog\Setup\CategorySetupFactory;

/**
 * @codeCoverageIgnore
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class InstallData implements InstallDataInterface
{
    /**
     * Eav setup factory
     * @var EavSetupFactory
     */
    private $eavSetupFactory;

    /**
     * Init
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(\Magento\Eav\Setup\EavSetupFactory $eavSetupFactory)
    {
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * {@inheritdoc}
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     * @SuppressWarnings(PHPMD.NPathComplexity)
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $installer = $setup;
        $installer->startSetup();
        $this->installEntities($setup);
        $installer->endSetup(); 
    }

    /**
     * Default entites and attributes
     *
     * @param array|null $entities
     * @return array
     *
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function installEntities($setup)
    {
        $attributes = [
            'is_serialized_data'       => [
                'type'                       => 'int',
                'label'                      => 'Add Serialize Data',
                'input'                      => 'select',
                'source'                     => 'Magento\Eav\Model\Entity\Attribute\Source\Boolean',
                'required'                   => false,
                'note'                       =>
                    'This data will save in sigle attribute serilized_data.',
                'sort_order'                 => 1,
                'apply_to'                   => 'simple,virtual',
                'is_configurable'            => false,
                'group'                      => 'Serialized Data',
            ],
            'serilized_data'  => [
                'type'                       => 'text',
                'label'                      => 'Serialize Data',
                'input'                      => 'text',
                'backend'                    => 'Vendor\Module\Model\Product\Attribute\Backend\Customserializeddata',
                'required'                   => false,
                'sort_order'                 => 2,
                'apply_to'                   => 'simple,virtual,configurable',
                'is_configurable'            => false,
                'group'                      => 'Serialize Data',
            ]
        ];

        $eavSetup = $this->eavSetupFactory->create();
        foreach ($attributes as $attrCode => $attr) {
            $eavSetup->addAttribute('catalog_product', $attrCode, $attr);
        }

        $entityTypeId = $eavSetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY);
        $attributeSetId = $eavSetup->getAttributeSetId($entityTypeId, 'Default');

        $groupName = 'Serialize Data';
        $eavSetup->updateAttributeGroup($entityTypeId, $attributeSetId, $groupName, 'sort_order', 41);
        $eavSetup->updateAttributeGroup($entityTypeId, $attributeSetId, $groupName, 'attribute_group_code', 'serialize-data');
        $eavSetup->updateAttributeGroup($entityTypeId, $attributeSetId, $groupName, 'tab_group_code', 'advanced');

        $eavSetup->addAttributeToGroup($entityTypeId, $attributeSetId, $groupName, 'is_serialized_data');
        $eavSetup->addAttributeToGroup($entityTypeId, $attributeSetId, $groupName, 'serilized_data');

        $connection = $setup->getConnection();
        $adminRuleTable = $setup->getTable('authorization_rule');
        $connection->update(
            $adminRuleTable,
            array('resource_id' => 'Vendor_Module::serilized_data'),
            array('resource_id = ?' => 'Magento_Sales::serilized_data')
        );

    }
}

Then I have created the form fields using product_form.xml using UI-components.

app\code\Vendor\Module\view\adminhtml\ui_component\product_form.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
   <fieldset name="serialize-data">
        <fieldset name="fieldset_test" sortOrder="10">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="scopeLabel" xsi:type="string">[GLOBAL]</item>
                </item>
            </argument>
            <settings>
                <label translate="true"/>
            </settings>
            <container>
                <field name="field_1" sortOrder="10" formElement="select">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="rawOptions" xsi:type="boolean">true</item>
                        </item>
                    </argument>
                    <settings>
                        <scopeLabel>[GLOBAL]</scopeLabel>
                        <label translate="true">Product Can Has Serialize Data</label>
                        <dataScope>field_1</dataScope>
                        <imports>
                            <link name="visible">${$.provider}:data.product.is_serialized_data</link>
                        </imports>
                    </settings>
                    <formElements>
                        <select>
                            <settings>
                                <options class="Magento\Config\Model\Config\Source\Yesno"/>
                            </settings>
                        </select>
                    </formElements>
                </field>
                <field name="field_2" sortOrder="20" formElement="input">
                    <settings>
                        <scopeLabel>[GLOBAL]</scopeLabel>
                        <label translate="true">Test Data</label>
                        <notice translate="true">Text Input going save as serialize-data/json data in serilized_data product's attribute attribute.</notice>
                        <dataScope>field_2</dataScope>
                        <imports>
                            <link name="visible">${$.provider}:data.product.is_serialized_data</link>
                        </imports>
                    </settings>
                </field>
            </container>
        </fieldset>
    </fieldset>
</form>

And the backend model for attribute is

Vendor\Module\Model\Product\Attribute\Backend\Customserializeddata.php

<?php

/**
 * Backend for serilized_data
 */
namespace Vendor\Module\Model\Product\Attribute\Backend;

class Customserializeddata
extends \Magento\Eav\Model\Entity\Attribute\Backend\Serialized  // I know this calss does not exist in magento 2.2.5 now but I have added it customly for my requirement which extends below (AbstractBackend) class
// extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend

{

    /**
     * Serialize or remove before saving
     *
     * @param \Magento\Catalog\Model\Product $product
     * @return void
     */
    public function beforeSave($product)
    {
        if ($product->hasIsSerializedData()) {
            if ($product->getIsSerializedData()) {
                parent::beforeSave($product);
            } else {
                $product->unsSerilizedData();
            }
        }
    }


    protected function _unserialize(\Magento\Framework\DataObject $product)
    {
        if ($product->hasIsSerializedData()) {
            if ($product->getIsSerializedData()) {
                parent::_unserialize($product);
            } else {
                $product->unsSerilizedData();
            }
        }
    }

}

Magento\Eav\Model\Entity\Attribute\Backend\Serialized.php

<?php

namespace Magento\Eav\Model\Entity\Attribute\Backend;
/**
 * "Serialized" attribute backend
 */
class Serialized extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
{
    /**
     * Serialize before saving
     *
     * @param \Magento\Framework\DataObject $object
     * @return $this
     */
    public function beforeSave($object)
    {
        // parent::beforeSave() is not called intentionally
        $attrCode = $this->getAttribute()->getAttributeCode();
        if ($object->hasData($attrCode)) {
            $object->setData($attrCode, serialize($object->getData($attrCode)));
        }
        return $this;
    }
    /**
     * Unserialize after saving
     *
     * @param \Magento\Framework\DataObject $object
     * @return $this
     */
    public function afterSave($object)
    {
        parent::afterSave($object);
        $this->_unserialize($object);
        return $this;
    }
    /**
     * Unserialize after loading
     *
     * @param \Magento\Framework\DataObject $object
     * @return $this
     */
    public function afterLoad($object)
    {
        parent::afterLoad($object);
        $this->_unserialize($object);
        return $this;
    }
    /**
     * Try to unserialize the attribute value
     *
     * @param \Magento\Framework\DataObject $object
     * @return $this
     */
    protected function _unserialize(\Magento\Framework\DataObject $object)
    {
        $attrCode = $this->getAttribute()->getAttributeCode();
        if ($object->getData($attrCode)) {
            try {
                $unserialized = unserialize($object->getData($attrCode));
                $object->setData($attrCode, $unserialized);
            } catch (\Exception $e) {
                $object->unsetData($attrCode);
            }
        }
        return $this;
    }
}

Currently serilized_data is displayed in tab in edit product page as text input and I can save and edit the values. But the fields created with the 'product_form.xml' can not be saved data into 'serilized_data' attribute.

Was it helpful?

Solution

I just missed to add the original attribute-Id serialize_data before field name in which I need to save it.

Which'll turn the product[field_1] post data to product[serialize_data][field_1]

See my updated file

app\code\Vendor\Module\view\adminhtml\ui_component\product_form.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
   <fieldset name="serialize-data">
        <fieldset name="fieldset_test" sortOrder="10">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="scopeLabel" xsi:type="string">[GLOBAL]</item>
                </item>
            </argument>
            <settings>
                <label translate="true"/>
            </settings>
            <container>
                <field name="field_1" sortOrder="10" formElement="select">
                    <argument name="data" xsi:type="array">
                        <item name="config" xsi:type="array">
                            <item name="rawOptions" xsi:type="boolean">true</item>
                        </item>
                    </argument>
                    <settings>
                        <scopeLabel>[GLOBAL]</scopeLabel>
                        <label translate="true">Product Can Has Serialize Data</label>
                        <dataScope>serialize_data.field_1</dataScope>
                        <imports>
                            <link name="visible">${$.provider}:data.product.is_serialized_data</link>
                        </imports>
                    </settings>
                    <formElements>
                        <select>
                            <settings>
                                <options class="Magento\Config\Model\Config\Source\Yesno"/>
                            </settings>
                        </select>
                    </formElements>
                </field>
                <field name="field_2" sortOrder="20" formElement="input">
                    <settings>
                        <scopeLabel>[GLOBAL]</scopeLabel>
                        <label translate="true">Test Data</label>
                        <notice translate="true">Text Input going save as serialize-data/json data in serilized_data product's attribute attribute.</notice>
                        <dataScope>serialize_data.field_2</dataScope>
                        <imports>
                            <link name="visible">${$.provider}:data.product.is_serialized_data</link>
                        </imports>
                    </settings>
                </field>
            </container>
        </fieldset>
    </fieldset>
</form>
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top