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.

There is 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 param among its constructor parameters. This is an instance of 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 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 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) {
        ...
    }
}

You can use one of the existing DataConverter implementations or create a new one, which will meet your needs. The new converter class must implement the Magento\Framework\DB\DataConverter\DataConverterInterface interface as well. But usually the usage of 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
        );
    }
}

As the result of setup upgrade the data stored in sample_config field of 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: