如何使用 Symfony 序列化创建初始对象

问题描述 投票:0回答:1

例如我有 SimpleDto 类

class SimpleDto implements GetPhoneInterface
{
    public string $name;

    public int $value;
}

还有json

{"name":"Jane"}

当我序列化它时,我得到无效的对象。

$serializer = self::getContainer()->get(SerializerInterface::class);
$dto = $serializer->deserialize($json, $dtoClass);

$dto 没有初始变量 $value。

如何确保在反序列化期间发生异常,该类具有未经验证的值?

如果使用序列化器无法解决这个问题,也许有某种方法可以使用验证器进行检查?

更新: 我尝试像这样实现它,但代码的行为不正确。另外,ObjectNormalizer是一个final类。 也许有人知道更好的解决方案?

class InitialObjectNormalizer extends ObjectNormalizer
{
    // circle check
    private array $visitedObjects = [];
    private array $errors = [];

    public function denormalize(mixed $data, string $type, ?string $format = null, array $context = [])
    {
        $data = parent::denormalize($data, $type, $format, $context);

        $this->handleObject($data);
        if (!empty($this->errors)) {
            throw new PartialDenormalizationException(null, $this->errors);
        }

        return $data;
    }

    public function handleObject($obj): void
    {
        if (in_array($obj, $this->visitedObjects, true)) {
            return;
        }
        $this->visitedObjects[] = $obj;

        $attributes = new ReflectionObject($obj);

        foreach ($attributes->getProperties() as $attribute) {
            if (!$attribute->isInitialized($obj)) {
                $this->errors[] = new NotNormalizableValueException('Attribute ' . $attribute->getName() . ' not initial',);
            } else {
                $value = $attribute->getValue($obj);
                if (is_array($value) || is_object($value)) {
                    $this->handleObject($value);
                }
            }
        }
    }
}
php symfony validation serialization
1个回答
0
投票

SerializerInterface 是一个

interface
,您可以拥有自己的实现。示例:

namespace App\Messenger\Serializer;

use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;

class MessageWithTokenDecoder implements SerializerInterface
{
    public function decode(array $encodedEnvelope): Envelope
    {
        $envelope = \json_decode($encodedEnvelope, true);

        try {
            // parse the data you received with your custom fields
            $data = $envelope['data'];
            $data['token'] = $envelope['token'];

            // other operations like getting information from stamps
        } catch (\Throwable $throwable) {
            // wrap any exception that may occur in the envelope to send it to the failure transport
            return new Envelope($throwable);
        }

        return new Envelope($data);
    }

    public function encode(Envelope $envelope): array
    {
        // this decoder does not encode messages, but you can implement it by returning
        // an array with serialized stamps if you need to send messages in a custom format
        throw new \LogicException('This serializer is only used for decoding messages.');
    }
}

然后你可以设置自己的序列化器:

# config/packages/messenger.yaml
framework:
    messenger:
        transports:
            my_transport:
                dsn: '%env(MY_TRANSPORT_DSN)%'
                serializer: 'App\Messenger\Serializer\MessageWithTokenDecoder'

代码取自此来源

当然,您可以完全不同地实现它,因为您的需求指导您,并且您也可以以不同的方式命名它。您还可以实现自定义验证器并进行设置,例如

# config/validator/validation.yaml
App\Entity\User:
    properties:
        name:
            - NotBlank: ~
            - App\Validator\ContainsAlphanumeric:
                mode: 'loose'

并像这样实现它

// src/Validator/ContainsAlphanumericValidator.php
namespace App\Validator;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\UnexpectedValueException;

class ContainsAlphanumericValidator extends ConstraintValidator
{
    public function validate(mixed $value, Constraint $constraint): void
    {
        if (!$constraint instanceof ContainsAlphanumeric) {
            throw new UnexpectedTypeException($constraint, ContainsAlphanumeric::class);
        }

        // custom constraints should ignore null and empty values to allow
        // other constraints (NotBlank, NotNull, etc.) to take care of that
        if (null === $value || '' === $value) {
            return;
        }

        if (!is_string($value)) {
            // throw this exception if your validator cannot handle the passed type so that it can be marked as invalid
            throw new UnexpectedValueException($value, 'string');

            // separate multiple types using pipes
            // throw new UnexpectedValueException($value, 'string|int');
        }

        // access your configuration options like this:
        if ('strict' === $constraint->mode) {
            // ...
        }

        if (preg_match('/^[a-zA-Z0-9]+$/', $value, $matches)) {
            return;
        }

        // the argument must be a string or an object implementing __toString()
        $this->context->buildViolation($constraint->message)
            ->setParameter('{{ string }}', $value)
            ->addViolation();
    }
}

代码取自此来源

当然,您需要自己编码才能自定义序列化器和/或验证器。

© www.soinside.com 2019 - 2024. All rights reserved.