Callback on serializer Symfony

前端 未结 4 1643
借酒劲吻你
借酒劲吻你 2020-12-21 16:45

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

相关标签:
4条回答
  • 2020-12-21 16:54

    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());
    
    0 讨论(0)
  • 2020-12-21 17:00

    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.

    0 讨论(0)
  • 2020-12-21 17:01

    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:

    1. add your custom normalizer to the default Serializer service
    2. add NormalizableInterface to your entities
    3. create a new Serializer service (or a local object as suggested by the docs) as you were trying to do.

    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 }
    
    0 讨论(0)
  • 2020-12-21 17:07

    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.

    0 讨论(0)
提交回复
热议问题