Я использовал сериализатор Symfony для сериализации моего объекта Recherche.
В объекте Recherche у меня есть подобъекты: Categorie и Lieu.
Когда я десериализую свой объект Recherche, все подобъекты преобразуются в массивы. Я бы хотел, чтобы они снова стали объектами.
Вот как я сериализовал свой объект:
$encoders = array(new JsonEncoder());
$normalizer = new ObjectNormalizer();
$normalizer->setIgnoredAttributes(array('parent', 'enfants'));
$normalizer->setCircularReferenceHandler(function ($object) {
return $object->getCode();
});
$normalizers = array($normalizer);
$serializer = new Serializer($normalizers, $encoders);
$rechercheJson= $serializer->serialize($recherche, 'json');
И вот как я его десериализую:
$encoders = array(new JsonEncoder());
$normalizer = new ObjectNormalizer();
$normalizer->setIgnoredAttributes(array('parent', 'enfants'));
$normalizer->setCircularReferenceHandler(function ($object) {
return $object->getCode();
});
$normalizers = array($normalizer);
$serializer = new Serializer($normalizers, $encoders);
$recherche = $serializer->deserialize($recherche_json, Recherche::class, 'json');
Я думаю, может быть, есть какое-то отношение к нормализатору, но я не могу найти в документации ничего, что могло бы мне помочь.
У кого-нибудь есть идея помочь?
Спасибо !
РЕДАКТИРОВАТЬ : Увидев этот пост: Денормализация вложенной структуры в объектах с помощью сериализатора Symfony 2
Я пробовал это:
$encoders = array(new JsonEncoder());
$normalizer = new ObjectNormalizer(null, null, null, new SerializationPropertyTypeExtractor());
$normalizer->setIgnoredAttributes(array('parent', 'enfants'));
$normalizer->setCircularReferenceHandler(function ($object) {
return $object->getCode();
});
$normalizers = array($normalizer, new ArrayDenormalizer());
$serializer = new Serializer($normalizers, $encoders);
$recherche = $serializer->deserialize($recherche_json, Recherche::class, 'json');
И SerializationPropertyTypeExtractor:
class SerializationPropertyTypeExtractor implements PropertyTypeExtractorInterface {
/**
* {@inheritdoc}
*/
public function getTypes($class, $property, array $context = array())
{
if (!is_a($class, Recherche::class, true)) {
return null;
}
if ('make' !== $property) {
return null;
}
if ('lieu' === $property)
{
return [new Type(Type::BUILTIN_TYPE_OBJECT, true, LieuRecherche::class)];
}
if ('categorie' === $property)
{
return [new Type(Type::BUILTIN_TYPE_OBJECT, true, Categorie::class)];
}
return null;
}
}
И это хорошо работает!
Да, пример может быть хорошим, я не понимаю :-)





Ссылка: мой комментарий. Я знаю, что вы используете сериализатор классическим способом, но я рекомендую вам применить рекомендуемый шаблон стратегии, чтобы вы имели полный контроль над компонентом и могли легко расширяться.
Идея состоит в том, чтобы создать отдельные классы для нормализации и денормализации следующим образом:
<?php
declare(strict_types=1);
namespace App\Denormalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Exception\CircularReferenceException;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
/**
* Class ConfigDenormalizer
* @package App\Denormalizer
*/
class ConfigDenormalizer implements DenormalizerInterface
{
/**
* @param mixed $data
* @param string $class
* @param null $format
* @param array $context
* @return array
*/
public function denormalize($data = [], $class, $format = null, array $context = array())
{
$result = [];
foreach($data as $key => $config) {
$result[ $config['attribute'] ] = $config['valorem'];
}
return $result;
}
/**
* @param mixed $data
* @param string $type
* @param null $format
* @return bool
*/
public function supportsDenormalization($data, $type, $format = null)
{
return $type === self::class;
}
}
<?php
declare(strict_types=1);
namespace App\Normalizer;
use Symfony\Component\Form\Form;
use Symfony\Component\Serializer\Exception\CircularReferenceException;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
/**
* Class WidgetConfigNormalizer
* @package App\Normalizer
*/
class WidgetAttributeNormalizer implements NormalizerInterface
{
/**
* @param object $form
* @param null $format
* @param array $context
* @return array
*/
public function normalize($form, $format = null, array $context = array()): array
{
$result = [];
foreach($form->getData() as $key => $value) {
$result[] = [
'attribute' => (string) $key,
'valorem' => (string) $value,
];
}
return $result;
}
/**
* @param mixed $form
* @param null $format
* @return bool
*/
public function supportsNormalization($form, $format = null)
{
if ($form instanceof Form) {
return $form->getName() === 'widgetAttribute';
}
}
}
и вы бы назвали это так:
//denormalize
$this->denormalizer->denormalize(
json_decode($response->getContent(), true),
ConfigDenormalizer::class
);
//normalize
$form = $this->formFactory->create(myConfigFormType::class);
$form->submit($data);
$this->normalizer->normalize($form);
Или, если вы хотите использовать сериализатор (обратите внимание, нам не нужен json_decode):
//deserialize
$array = $this->serializer->deserialize(
$response->getContent(),
ConfigDenormalizer::class,
'json'
);
//serialize
$json = $this->serialize->serialize($form, 'json');
Конечно, в вашем денормализаторе вы можете преобразовать свой массив в простой старый объект (сущность) php. или просто выведите массив, выбор за вами.
Таким образом, все, что вам нужно сделать, это ввести SerializerInterface в ваши контроллеры следующим образом:
use Symfony\Component\Serializer\SerializerInterface;
class EmbedController extends Controller
{
/**
* @var SerializerInterface
*/
private $serializer;
public function __construct(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
}
Этот метод значительно упрощает модульное тестирование, поскольку все отделено, поэтому его можно смоделировать. :)
Также стоит проверить документацию: https://symfony.com/doc/current/components/serializer.html
Особенно изображение вверху, это отличная подсказка памяти о том, в каком направлении вы должны использовать каждый класс.
Надеюсь это поможет.
Если вы используете Autowiring, вам не нужно определять свои (де) нормализаторы как службы или помечать их, это должно работать сразу из коробки. раз уж вы сделали composer require serializer;)
Спасибо, Эдвард. Если я хорошо понимаю, ты ведь делаешь почти всю работу сам? Сериализатор Symfony почти бесполезен, не так ли?
Вам решать, если вы хотите сериализовать или десериализовать без настраиваемых (де) нормализаторов, вы используете службу сериализатора напрямую $json = $this->serializer->serialize($object, 'json');, но в вашем вопросе вам нужна настраиваемая структура, для этого вам нужны настраиваемые (де) нормализаторы.
Я нашел, как это сделать. Как вы видите в части моего вопроса, посвященной редактированию, я протестировал решение, которое, похоже, не сработало, но, наконец, работает хорошо. Спасибо за помощь
У меня была аналогичная проблема, и я попытался решить ее с помощью настраиваемого PropertyTypeExtractor. Поскольку у меня много сущностей с вложенными объектами, это было довольно громоздко, и это не работает, когда вложенный объект снова имеет вложенный объект.
Я нашел лучшее решение, используя PhpDocExtractor и ReflectionExtractor, которые извлекают для вас информацию о свойствах.
$encoder = [new JsonEncoder()];
$extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]);
$normalizer = [new ArrayDenormalizer(), new ObjectNormalizer(null, null, null, $extractor)];
$serializer = new Serializer($normalizer, $encoder);
$result = $serializer->deserialize($data,someEntity::class,'json');
Это делает всю работу за меня. Надеюсь, это кому-то поможет.
Я обычно использую шаблон стратегии с компонентом сериализатора Symfony. Он позволяет вам точно определить, как должен выглядеть нормализованный и денормализованный объект / массив. Я пришлю пример чуть позже.