You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为JmsSerializer配置MySQL与ElasticSearch差异化序列化逻辑?

How to Implement Target-Specific Serialization with JMS Serializer (MySQL vs ElasticSearch)

Got it, let's break down how to handle this scenario where we need different serialization/deserialization rules for MySQL and ElasticSearch using JMS Serializer. The core idea is to create a custom handler that checks a context flag to decide whether to apply the empty string ↔ "def" conversion for ElasticSearch, while leaving MySQL data untouched.

Step 1: Create a Custom String Handler

We'll build a handler that overrides the default string serialization/deserialization logic, but only applies our custom rules when the target storage is ElasticSearch.

use JMS\Serializer\Handler\BaseHandler;
use JMS\Serializer\Context;
use JMS\Serializer\VisitorInterface;

class TargetSpecificStringHandler extends BaseHandler
{
    private const TARGET_ELASTICSEARCH = 'elasticsearch';
    private const DEFAULT_VALUE = 'def';

    public function serializeString(VisitorInterface $visitor, string $value, array $type, Context $context)
    {
        // Check if we're targeting ElasticSearch
        if ($context->get('target_storage') === self::TARGET_ELASTICSEARCH) {
            // Replace empty string with "def"
            $value = $value === '' ? self::DEFAULT_VALUE : $value;
        }

        // Delegate to the default string serialization
        return $visitor->visitString($value, $type, $context);
    }

    public function deserializeString(VisitorInterface $visitor, string $value, array $type, Context $context)
    {
        // Check if we're targeting ElasticSearch
        if ($context->get('target_storage') === self::TARGET_ELASTICSEARCH) {
            // Replace "def" back to empty string
            $value = $value === self::DEFAULT_VALUE ? '' : $value;
        }

        // Delegate to the default string deserialization
        return $visitor->visitString($value, $type, $context);
    }
}

Step 2: Register the Handler with JMS Serializer

Next, we need to register our custom handler with the JMS Serializer instance. Here's how to do it in a typical setup:

use JMS\Serializer\SerializerBuilder;

// Build the serializer and register our handler
$serializer = SerializerBuilder::create()
    ->addDefaultHandlers()
    ->configureHandlers(function ($handlerRegistry) {
        $handlerRegistry->registerHandler('serialization', 'string', 'json', [new TargetSpecificStringHandler(), 'serializeString']);
        $handlerRegistry->registerHandler('deserialization', 'string', 'json', [new TargetSpecificStringHandler(), 'deserializeString']);
        // If you use other formats (like xml), add those too
        $handlerRegistry->registerHandler('serialization', 'string', 'xml', [new TargetSpecificStringHandler(), 'serializeString']);
        $handlerRegistry->registerHandler('deserialization', 'string', 'xml', [new TargetSpecificStringHandler(), 'deserializeString']);
    })
    ->build();

Step 3: Use the Serializer with Context Parameters

Now, when you need to serialize/deserialize for MySQL or ElasticSearch, just pass the target_storage parameter in the context:

Example Entity

First, let's define a sample entity to test with:

use JMS\Serializer\Annotation as Serializer;

class Product
{
    #[Serializer\Type('string')]
    private string $name = '';

    #[Serializer\Type('string')]
    private string $description = '';

    // Constructor, getters, setters...
    public function __construct(string $name = '', string $description = '')
    {
        $this->name = $name;
        $this->description = $description;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function getDescription(): string
    {
        return $this->description;
    }
}

Serialization for MySQL

Empty strings stay as-is:

$product = new Product('', 'Some description');

// Serialize for MySQL
$mysqlJson = $serializer->serialize($product, 'json', [
    'target_storage' => 'mysql'
]);

// Output: {"name":"","description":"Some description"}
echo $mysqlJson;

Serialization for ElasticSearch

Empty strings are replaced with "def":

// Serialize for ElasticSearch
$esJson = $serializer->serialize($product, 'json', [
    'target_storage' => 'elasticsearch'
]);

// Output: {"name":"def","description":"Some description"}
echo $esJson;

Deserialization for ElasticSearch

"def" gets converted back to empty string:

// Deserialize from ElasticSearch JSON
$deserializedProduct = $serializer->deserialize($esJson, Product::class, 'json', [
    'target_storage' => 'elasticsearch'
]);

// Will output empty string
echo $deserializedProduct->getName();

Deserialization for MySQL

No conversion happens:

// Deserialize from MySQL JSON
$deserializedMysqlProduct = $serializer->deserialize($mysqlJson, Product::class, 'json', [
    'target_storage' => 'mysql'
]);

// Will output empty string (matches original)
echo $deserializedMysqlProduct->getName();

Alternative: Using Serialization Groups (Optional)

If you prefer, you could also use serialization groups instead of context parameters. For example, define groups like mysql and elasticsearch, then modify the handler to check the active groups instead of the context parameter. But the context parameter approach is more flexible for dynamic target switching.


内容的提问来源于stack exchange,提问作者Serhii Smirnov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:33:39