For example I have SimpleDto class
class SimpleDto implements GetPhoneInterface
{
public string $name;
public int $value;
}
And json
{"name":"Jane"}
When I serialize it, i get not valid object.
$serializer = self::getContainer()->get(SerializerInterface::class);
$dto = $serializer->deserialize($json, $dtoClass);
$dto has not initial variable $value.
How can I make sure that during deserialization an exception occurs that the class has unvalidated values?
If this cannot be solved using a serializer, maybe there is some way to check using a validator?
Upd:
I tried to implement it like this, but the code behaves incorrectly. In addition, ObjectNormalizer is a final class.
Maybe someone knows a better solution?
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);
}
}
}
}
}
2
Answers
SerializerInterface is an
interface
and you can have your own implementation. Example:and then you can set your own serializer:
Code taken from this source.
Of course, you can implement it completely differently, as your requirements direct you and you can name it differently too. You can also implement a custom validator and set it up, like
and implement it like
Code taken from this source.
Of course, you will need to do your own coding in order to customize your serializer and/or validator.
Try rewriting your DTO using a constructor:
The standard
ObjectNormalizer
will now throw aMissingConstructorArgumentsException
which you can handle in your code.If you can not rewrite the DTO, you can implement a custom denormalizer and check whether all required fields are present. This is a very basic example, adapt to your own need.
You can find more about custom denormalizers in the Symfony documentation.