Как создать свой пользовательский конструктор контекста

Дата обновления перевода 2024-07-27

Как создать свой пользовательский конструктор контекста

Компонент Serializer использует нормализаторы и кодировщики для преобразования любых данных в любую структуру данных (например, JSON). Процесс сериализации может быть сконфигурирован благодаря контексту сериализации , который может быть создан благодаря конструкторам контекста .

Каждый встроенный нормализатор/кодировщик имеет свой соответствующий конструктор контекста. Однако вы вы можете захотеть создать собственный конструктор контекста для ваших настраиваемых нормализаторов.

Создание конструктора контекста

Представим, что вы хотите по-другому обрабатывать денормализацию дат, если они поступают из унаследованной системы, преобразуя даты в null, если сериализованное значение 0000-00-00. Для этого сначала нужно создать свой нормализатор:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// src/Serializer/ZeroDateTimeDenormalizer.php
namespace App\Serializer;

use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;

final class ZeroDateTimeDenormalizer implements DenormalizerInterface, DenormalizerAwareInterface
{
    use DenormalizerAwareTrait;

    public function denormalize($data, string $type, string $format = null, array $context = []): mixed
    {
        if ('0000-00-00' === $data) {
            return null;
        }

        unset($context['zero_datetime_to_null']);

        return $this->denormalizer->denormalize($data, $type, $format, $context);
    }

    public function supportsDenormalization($data, string $type, string $format = null, array $context = []): bool
    {
        return true === ($context['zero_datetime_to_null'] ?? false)
            && is_a($type, \DateTimeInterface::class, true);
    }
}

Теперь вы можете приводить нулевые даты к null при денормализации:

1
2
$legacyData = '{"updatedAt": "0000-00-00"}';
$serializer->deserialize($legacyData, MyModel::class, 'json', ['zero_datetime_to_null' => true]);

Теперь, чтобы избежать необходимости помнить об этом специфическом ключе контекста zero_date_to_null, можно создать специальный конструктор контекста:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/Serializer/LegacyContextBuilder
namespace App\Serializer;

use Symfony\Component\Serializer\Context\ContextBuilderInterface;
use Symfony\Component\Serializer\Context\ContextBuilderTrait;

final class LegacyContextBuilder implements ContextBuilderInterface
{
    use ContextBuilderTrait;

    public function withLegacyDates(bool $legacy): static
    {
        return $this->with('zero_datetime_to_null', $legacy);
    }
}

И наконец, используйте его для создания контекста сериализации:

1
2
3
4
5
6
7
$legacyData = '{"updatedAt": "0000-00-00"}';

$context = (new LegacyContextBuilder())
    ->withLegacyDates(true)
    ->toArray();

$serializer->deserialize($legacyData, MyModel::class, 'json', $context);