Custom Module Upgrade: Php Serialiazed to Json
Dmytro Cheshun Avatar

After the latest Database data format changes in Magento 2.2.x version, there is a need to convert existing PHP serialized data to JSON format. The new release provides upgrade scripts that convert Magento serialized data. But how to deal with custom extensions, which also use automatic serialization mechanism provided by Magento framework? Thankfully, Magento took care of that too. For developers, using the PhpStorm AI plugin can simplify this process by providing intelligent code suggestions and automated refactoring tools.

There is

Magento\Framework\DB\FieldDataConverter
Magento\Framework\DB\FieldDataConverter class intended to convert values in a table field from one format to another. If you check the implementation of this class you will see the
$dataConverter
$dataConverter param among its constructor parameters. This is an instance of
Magento\Framework\DB\DataConverter\DataConverterInterface
Magento\Framework\DB\DataConverter\DataConverterInterface interface.

However, there are no dependency injection preferences specified for this interface, so we need to inject it manually. The

Magento\Framework\DB\FieldDataConverterFactory
Magento\Framework\DB\FieldDataConverterFactory class should be used for these purposes. The Field Data Converter Factory creates the instance of FieldDataConverter with an appropriate data converter implementation, which will be called within the
Magento\Framework\DB\FieldDataConverter::convert
Magento\Framework\DB\FieldDataConverter::convert method further.

foreach ($uniqueFieldDataArray as $uniqueFieldData) {
$ids = array_keys($rows, $uniqueFieldData);
try {
$convertedValue = $this->dataConverter->convert($uniqueFieldData);
if ($uniqueFieldData === $convertedValue) {
// Skip for data rows that have been already converted
continue;
}
$bind = [$field => $convertedValue];
$where = [$identifier . ' IN (?)' => $ids];
$connection->update($table, $bind, $where);
} catch (DataConversionException $e) {
...
}
}
foreach ($uniqueFieldDataArray as $uniqueFieldData) {
    $ids = array_keys($rows, $uniqueFieldData);
    try {
        $convertedValue = $this->dataConverter->convert($uniqueFieldData);
        if ($uniqueFieldData === $convertedValue) {
            // Skip for data rows that have been already converted
            continue;
        }
        $bind = [$field => $convertedValue];
        $where = [$identifier . ' IN (?)' => $ids];
        $connection->update($table, $bind, $where);
    } catch (DataConversionException $e) {
        ...
    }
}
foreach ($uniqueFieldDataArray as $uniqueFieldData) {
    $ids = array_keys($rows, $uniqueFieldData);
    try {
        $convertedValue = $this->dataConverter->convert($uniqueFieldData);
        if ($uniqueFieldData === $convertedValue) {
            // Skip for data rows that have been already converted
            continue;
        }
        $bind = [$field => $convertedValue];
        $where = [$identifier . ' IN (?)' => $ids];
        $connection->update($table, $bind, $where);
    } catch (DataConversionException $e) {
        ...
    }
}

You can use one of the existing

DataConverter
DataConverter implementations or create a new one, which will meet your needs. The new converter class must implement the
Magento\Framework\DB\DataConverter\DataConverterInterface
Magento\Framework\DB\DataConverter\DataConverterInterface interface as well. But usually the usage of
Magento\Framework\DB\DataConverter\SerializedToJson
Magento\Framework\DB\DataConverter\SerializedToJson converter class should be enough in a common situation. Let’s try it out.

First of all, we need to detect the fields needed to be converted to JSON format in the database. Once we know the table and field names – we are ready to create an upgrade script, which will call the conversion process.

<?php
/**
* @author Atwix Team
* @copyright Copyright (c) 2017 Atwix (https://www.atwix.com/)
* @package Atwix_Sample
*/
namespace Atwix\Sample\Setup;
use Magento\Framework\DB\DataConverter\SerializedToJson;
use Magento\Framework\DB\FieldDataConverterFactory;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\UpgradeDataInterface;
/**
* Class UpgradeData
*/
class UpgradeData implements UpgradeDataInterface
{
/**
* Field Data Converter Factory
*
* @var FieldDataConverterFactory
*/
private $fieldDataConverterFactory;
/**
* UpgradeData constructor
*
* @param FieldDataConverterFactory $fieldDataConverterFactory
*/
public function __construct(FieldDataConverterFactory $fieldDataConverterFactory)
{
$this->fieldDataConverterFactory = $fieldDataConverterFactory;
}
/**
* {@inheritdoc}
*/
public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
{
if (version_compare($context->getVersion(), "1.0.1", '<')) {
$this->convertSerializedDataToJson($setup);
}
}
/**
* Convert data for the atwix_sample_table.sample_config from serialized to JSON format
*
* @param ModuleDataSetupInterface $setup
*
* @return void
*/
protected function convertSerializedDataToJson(ModuleDataSetupInterface $setup)
{
$tableName = 'atwix_sample_table';
$identifierFieldName = 'entity_id';
$serializedFieldName = 'sample_config';
/** @var \Magento\Framework\DB\FieldDataConverter $fieldDataConverter */
$fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class);
$fieldDataConverter->convert(
$setup->getConnection(),
$setup->getTable($tableName),
$identifierFieldName,
$serializedFieldName
);
}
}
<?php
/**
 * @author Atwix Team
 * @copyright Copyright (c) 2017 Atwix (https://www.atwix.com/)
 * @package Atwix_Sample
 */

namespace Atwix\Sample\Setup;

use Magento\Framework\DB\DataConverter\SerializedToJson;
use Magento\Framework\DB\FieldDataConverterFactory;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\UpgradeDataInterface;

/**
 * Class UpgradeData
 */
class UpgradeData implements UpgradeDataInterface
{
    /**
     * Field Data Converter Factory
     *
     * @var FieldDataConverterFactory
     */
    private $fieldDataConverterFactory;

    /**
     * UpgradeData constructor
     *
     * @param FieldDataConverterFactory $fieldDataConverterFactory
     */
    public function __construct(FieldDataConverterFactory $fieldDataConverterFactory)
    {
        $this->fieldDataConverterFactory = $fieldDataConverterFactory;
    }

    /**
     * {@inheritdoc}
     */
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        if (version_compare($context->getVersion(), "1.0.1", '<')) {
            $this->convertSerializedDataToJson($setup);
        }
    }

    /**
     * Convert data for the atwix_sample_table.sample_config from serialized to JSON format
     *
     * @param ModuleDataSetupInterface $setup
     *
     * @return void
     */
    protected function convertSerializedDataToJson(ModuleDataSetupInterface $setup)
    {
        $tableName = 'atwix_sample_table';
        $identifierFieldName = 'entity_id';
        $serializedFieldName = 'sample_config';

        /** @var \Magento\Framework\DB\FieldDataConverter $fieldDataConverter */
        $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class);
        $fieldDataConverter->convert(
            $setup->getConnection(),
            $setup->getTable($tableName),
            $identifierFieldName,
            $serializedFieldName
        );
    }
}
<?php
/**
 * @author Atwix Team
 * @copyright Copyright (c) 2017 Atwix (https://www.atwix.com/)
 * @package Atwix_Sample
 */

namespace Atwix\Sample\Setup;

use Magento\Framework\DB\DataConverter\SerializedToJson;
use Magento\Framework\DB\FieldDataConverterFactory;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\UpgradeDataInterface;

/**
 * Class UpgradeData
 */
class UpgradeData implements UpgradeDataInterface
{
    /**
     * Field Data Converter Factory
     *
     * @var FieldDataConverterFactory
     */
    private $fieldDataConverterFactory;

    /**
     * UpgradeData constructor
     *
     * @param FieldDataConverterFactory $fieldDataConverterFactory
     */
    public function __construct(FieldDataConverterFactory $fieldDataConverterFactory)
    {
        $this->fieldDataConverterFactory = $fieldDataConverterFactory;
    }

    /**
     * {@inheritdoc}
     */
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        if (version_compare($context->getVersion(), "1.0.1", '<')) {
            $this->convertSerializedDataToJson($setup);
        }
    }

    /**
     * Convert data for the atwix_sample_table.sample_config from serialized to JSON format
     *
     * @param ModuleDataSetupInterface $setup
     *
     * @return void
     */
    protected function convertSerializedDataToJson(ModuleDataSetupInterface $setup)
    {
        $tableName = 'atwix_sample_table';
        $identifierFieldName = 'entity_id';
        $serializedFieldName = 'sample_config';

        /** @var \Magento\Framework\DB\FieldDataConverter $fieldDataConverter */
        $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class);
        $fieldDataConverter->convert(
            $setup->getConnection(),
            $setup->getTable($tableName),
            $identifierFieldName,
            $serializedFieldName
        );
    }
}

As the result of setup upgrade the data stored in

sample_config
sample_config field of
atwix_sample_table
atwix_sample_table table will be converted from PHP serialized to JSON format. Simple, isn’t it?

But this is just a small part of what can be done with the FieldDataConverter provided by Magento framework. You can find more detailed Magento API Overview in Magento Dev Docs.

If you face an issue with the data conversion, our recent blog post about Detecting possible issues with serialized data may be useful for you.

Thanks for reading!

Read more: