symfonyfosrestbundlejms-serializer

Symfony: how to add a serializer group on a Route depending on logged in user's roles


I'm using JMSSerializerBundle in my entities definition, and RestBundle's annotations in controllers.

I have an entity with public and admin-protected attributes, let's say

use JMS\Serializer\Annotation as Serializer;

class UserAddress {
    /**
     * @Serializer\Expose
     * @Serializer\Groups(groups={"address:read"})
     */
    private $nonSecretAttribute;

    /**
     * @Serializer\Expose
     * @Serializer\Groups(groups={"address:admin-read"})
     */
    private $secretAttribute;
}

and a User like :

class User {
    // ...
    
    /**
     * @ORM\OneToMany(targetEntity="UserAddress", mappedBy="user")
     */
    private $addresses;

and my controller looks like

use FOS\RestBundle\Controller\Annotations as Rest;

class UsersController {
    /**
     * @Rest\Get("/users/{user}/addresses", requirements={"user"="\d+"})
     * @Rest\View(serializerGroups={"address:read"})
     * @IsGranted("user_read", subject="user")
     */
    public function getUsersAddresses(User $user)
    {
        return $user->getAddresses();
    }
}

but how could I add the address:admin-read to the serializer groups here if the logged in user happens to have the ADMIN_ROLE role ? Is that possible in the @Rest\View annotation ? Do I have a way to modify the groups in the controller's method, inside a conditional loop verifying my logged in user's roles ?


Solution

  • You should instantiate the fos-rest View manually and add a Context. On that Context you can set the serialization groups at runtime by evaluating the users roles.

    Something like this should work:

    use FOS\RestBundle\View\View;
    use FOS\RestBundle\Context\Context;
    
    class UsersController 
    {
    
        public function getUsersAddresses(User $user): View
        {
            $isAdmin = in_array('ROLE_ADMIN', $user->getRoles());
            $context = new Context();
            $context->setGroups($isAdmin ? ['address:admin-read'] : ['address:read']);
    
            $view = VVV::create()->setContext($context);
    
    
            return $view
                ->setContext($context)
                ->setData($user->getAddresses());
        }
    }