Я запускаю Symfony 2.7, и я пытаюсь вывести объект (объект Doctrine) как JSON.
Когда я нормализую объект, я хочу преобразовать некоторые его значения. Для этого я нашел метод setCallbacks в документации, но я не понимаю, как применить его к моему делу.
Есть ли способ вызвать метод setCallbacks в нормализаторе, который задается при вызове службы сериализатора Symfonys?
Вот краткий пример того, чего я пытаюсь достичь:
//ExampleController.php public function getJSONOrderByIdAction($id) { $serializer = $this->get('serializer'); $normalizer = $serializer->getNormalizer(); // <- This is what I'm unable to do $dateTimeToString = function ($dateTime) { return $dateTime instanceof \DateTime ? $dateTime->format(\DateTime::ISO8601) : ''; }; $normalizer->setCallbacks(['time' => $dateTimeToString]); $order = $this->getDoctrine()->find("AppBundle:Order", $id); return new JsonResponse(["order" => $serializer->normalize($order, null, ["groups" => ["public"]])]); }
Я знаю, что большинство людей переключилось на JMS-сериализатор. Кажется, что встроенный сериализатор должен иметь возможность обрабатывать то, что я пытаюсь достичь.
Служба Serializer по умолчанию создается во время фазы ввода зависимостей, а интерфейс Serializer не позволяет редактировать (полный) поиск нормализаторов.
Я думаю, что у вас есть (по крайней мере) три варианта:
Я думаю, что в вашем сценарии предпочтителен случай 1 (поскольку 2 становится довольно скучным).
Я бы сделал что-то подобное; сначала создайте пользовательский Normalizer
<?php namespace AppBundle; class DateTimeNormalizer extends SerializerAwareNormalizer implements NormalizerInterface, DenormalizerInterface { /** * {@inheritdoc} */ public function normalize($object, $format = null, array $context = array()) { return $object->format(\DateTime::ISO8601); } /** * {@inheritdoc} */ public function denormalize($data, $class, $format = null, array $context = array()) { return new $class($data); } /** * Checks if the given class is a DateTime. * * @param mixed $data Data to normalize. * @param string $format The format being (de-)serialized from or into. * * @return bool */ public function supportsNormalization($data, $format = null) { return $data instanceof \DateTime; } /** * Checks if the given class is a DateTime. * * @param mixed $data Data to denormalize from. * @param string $type The class to which the data should be denormalized. * @param string $format The format being deserialized from. * * @return bool */ public function supportsDenormalization($data, $type, $format = null) { $class = new \ReflectionClass($type); return $class->isSubclassOf('\DateTime'); } }
Затем зарегистрируйте его в своих службах:
# app/config/services.yml services: datetime_normalizer: class: AppBundle\DateTimeNormalizer tags: - { name: serializer.normalizer }
Мое собственное решение
Следуя совету giosh94mhz, я попытался переключиться на JMS Serializer, но в итоге вернулся к сериализатору Symfonys.
JMS Serializer представил свои собственные проблемы и, ища ответы на эти вопросы, я наткнулся на сообщение в блоге Томаса Джарранда, которое отлично поработало, объясняя, как создавать и внедрять собственные нормализаторы в Symfony.
По-моему, вы, кажется, пытаетесь слишком усложнить ситуацию. Вот такой подход, который я сделал, когда мне нужно было сериализовать мои объекты как JSON:
PHP 2.5 и выше позволяет реализовать метод jsonSerialize для ваших объектов и просто вызвать json_encode непосредственно на вашем объекте.
Если вы все еще используете PHP 2.4, вам просто нужно вручную вызвать jsonSerialize()
на ваших объектах.
Например:
/** * @ORM\Entity */ class MyEntity { ... public function jsonSerialize() { $data = array("foo" => $this->bar()); // add other data here ... return $data } }
А затем в вызове кода:
// for PHP 2.5 and up: $normalized = json_encode($myEntityInstance); // for PHP 2.4 and below $normalized = json_encode($myEntityInstance->jsonSerialize());