Search code examples
symfonyjmsserializerbundlejms-serializer

How do I create a custom exclusion strategy for JMS Serializer that allows me to make run-time decisions about whether to include a particular field?


As the title says, I am trying to make a run-time decision on whether or not to include fields in the serialization. In my case, this decision will be based on permissions.

I am using Symfony 2, so what I'm looking to do is add an additional annotation called @ExcludeIf which accepts a security expression.

I can handle the annotation parsing and storing of the meta data, but I am not able to see how to integrate a custom exclusion strategy with the library.

Any suggestions?

Note: exclusion strategies are an actual construct in the JMS codebase, I just haven't been able to figure out the best way to integrate an extra on top of the others

PS: I had asked about this before and was pointed to using groups. For various reasons this is a very poor solution for my needs.


Solution

  • You just have to create a class that implements JMS\Serializer\Exclusion\ExclusionStrategyInterface

    <?php
    
    namespace JMS\Serializer\Exclusion;
    
    use JMS\Serializer\Metadata\ClassMetadata;
    use JMS\Serializer\Metadata\PropertyMetadata;
    use JMS\Serializer\Context;
    
    interface ExclusionStrategyInterface
    {
        /**
         * Whether the class should be skipped.
         *
         * @param ClassMetadata $metadata
         *
         * @return boolean
         */
        public function shouldSkipClass(ClassMetadata $metadata, Context $context);
    
        /**
         * Whether the property should be skipped.
         *
         * @param PropertyMetadata $property
         *
         * @return boolean
         */
        public function shouldSkipProperty(PropertyMetadata $property, Context $context);
    }
    

    In your case, you can implement your own custom logic in the shouldSkipProperty method and always return false for shouldSkipClass.

    Example of implementation can be found in the JMS/Serializer repository

    We will reference the created service as acme.my_exclusion_strategy_service below.


    In your controller action:

    <?php
    
    use Symfony\Component\HttpFoundation\Response;
    use JMS\Serializer\SerializationContext;
    
    // ....
    
    $context = SerializationContext::create()
        ->addExclusionStrategy($this->get('acme.my_exclusion_strategy_service'));
    
    $serial = $this->get('jms_serializer')->serialize($object, 'json', $context);
    
    return new Response($serial, Response::HTTP_OK, array('Content-Type' => 'application/json'));
    

    Or if you are using FOSRestBundle

    <?php
    
    use FOS\RestBundle\View;
    use JMS\Serializer\SerializationContext;
    
    // ....
    
    $context = SerializationContext::create()
        ->addExclusionStrategy($this->get('acme.my_exclusion_strategy_service'))
    
    $view = new View($object);
    $view->setSerializationContext($context);
    
    // or you can create your own view factory that handles the creation
    // of the context for you
    
    return $this->get('fos_rest.view_handler')->handle($view);