例如我有 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);
}
}
}
}
}
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();
}
}
代码取自此来源。
当然,您需要自己编码才能自定义序列化器和/或验证器。