I\'m running Symfony 2.7 and I\'m trying output an object (Doctrine entity) as JSON.
When I\'m normalizing the object I want to convert some of it\'s values. To do t
In my opinion, you seem to be trying to over-complicate things. Here's the approach I've taken when I needed to serialize my entities as JSON:
PHP 2.5 and above allows you to implement the jsonSerialize method on your objects and just call json_encode directly on your object.
If you are still using PHP 2.4, you just need to manually call jsonSerialize()
on your objects.
For example:
/**
* @ORM\Entity
*/
class MyEntity {
...
public function jsonSerialize() {
$data = array("foo" => $this->bar());
// add other data here ...
return $data
}
}
And then in calling code:
// for PHP 2.5 and up:
$normalized = json_encode($myEntityInstance);
// for PHP 2.4 and below
$normalized = json_encode($myEntityInstance->jsonSerialize());
You can use callback normalizer of K. Dunglas component.
You can see that in ObjectNormalizer (in normalize method)
if (isset($this->callbacks[$attribute])) {
$attributeValue = call_user_func($this->callbacks[$attribute], $attributeValue);
}
This mean that you must use in callback array key the name of property you wan't to normalize.
For example in my entity I have field named "name" of type "pgarray" (like array for postgresql). I wan't to normalize this data. Instead array I want a string.
/**
* $object represent the property "name" because callback is attached to name property (setCallback)
*/
$nameCallback = function ($object, $outerObject = null) {
return $object[0];
};
$this->normalizer->setCallbacks(['name' => $dateCallback]);
Just remember since Symfony 4.2 you must use $context in DI to use callback.
The default Serializer service is created during dependency injection phase, and the Serializer interface do not allow editing of (full) retrieval of normalizers.
I think you have (at least) three choice here:
I think in your scenario, case 1 is preferred (since 2 becomes boring pretty fast).
I would do something like this; first create a custom 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');
}
}
Then register it to your services:
# app/config/services.yml
services:
datetime_normalizer:
class: AppBundle\DateTimeNormalizer
tags:
- { name: serializer.normalizer }
My own solution
Following the advice from giosh94mhz I tried switching to JMS Serializer but ended up going back to Symfonys serializer.
JMS Serializer presented it's own issues and while searching for answers for those I stumbled upon a blog post by Thomas Jarrand that did an excellent job explaining how to make and implement your own normalizers in Symfony.