Search code examples
phpsymfonyfosrestbundlejmsserializerbundle

JMS Serializer Overriding Groups in FOSRestBundle


I read this article about overriding groups of child properties:

use JMS\Serializer\SerializationContext;

$context = SerializationContext::create()->setGroups(array(
    'Default', // Serialize John's name
    'manager_group', // Serialize John's manager
    'friends_group', // Serialize John's friends

    'manager' => array( // Override the groups for the manager of John
        'Default', // Serialize John manager's name
        'friends_group', // Serialize John manager's friends. If you do not override the groups for the friends, it will default to Default.
    ),

    'friends' => array( // Override the groups for the friends of John
        'manager_group' // Serialize John friends' managers.

        'manager' => array( // Override the groups for the John friends' manager
            'Default', // This would be the default if you did not override the groups of the manager property.
        ),
    ),
));
$serializer->serialize($john, 'json', $context);

In FOSRestBundle I am using the @View annotation with the serializerGroups property:

/**
 * @Rest\Get("/api/users/{id}", name="api_get_user")
 * @Rest\View(serializerGroups={"Default", "detail", "friends":{"Default"})
 */
public function getAction(Request $request, User $user = null)
{
    return $user;
}

How can I override child properties using that annotation?


Solution

  • If someone finds a better and shorter way with annotations I can award the bounty (since I can't get it back).

    The only way to override nested properties' groups is to get the serializer context from the view and set the groups from there. Here it is:

    /**
     * @Rest\Get("/api/users/profile", name="api_get_profile")
     */
    public function profileAction(Request $request)
    {
        $user = $this->getUser();
    
        // sets different groups for nested properties
        $view = $this->view($user);
        $view->getContext()->setGroups(array(
            'Default',
            'user_detail',
            'user_profile',
            'friends' => array(
                'Default',
            )
        ));
    
        return $this->handleView($view);
    }
    

    This way my profileAction will return an user with all the user_detail and user_profile groups, but the items in the friends property, which contains an array of User, will just contain the properties defined in the Default group.

    This is the result:

    {
        "id": 532,
        "username": "someuser",
        "email": "[email protected]",
        "enabled": true,
        "last_login": "2017-11-10T09:45:51+01:00",
        "notification_id": "ABC",
        "avatar_id": 3,
        "friends": [
            {
                "id": 530,
                "username": "anotheruser",
                "avatar_id": 5
            },
            {
                "id": 554,
                "username": "johndoe",
                "avatar_id": 7
            }
        ]
    }