Search code examples
symfonyjmsserializerbundlejms-serializer

JMS Serializer: how to propagate group exclusion for properties without adding annotations everywhere?


I am building an API with Symfony and JMS Serializer (via FOSRestundle) that exposes trees. I've created an Tree entity that contains an id, a title and the root node of the tree. I've created a Node entity too, containg the chaining between nodes.

My API contains a public part and an admin part, and I want trees to be exposed differently according if the controller belongs to one or the other:

  • in the public api, I want the id and the title of my tree only to be visible
  • in the admin api, I want all the properties of the tree to be visible, including the root node.

I've come to the following code:

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serializer;

/**
 * @ORM\Entity(repositoryClass="App\Repository\TreeRepository")
 */
class Tree {

    /**
     * Unique ID to identify the tree
     *
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @Serializer\Groups({"ADMIN", "API"})
     */
    private $id;

    /**
     * Name of the tree (example = a failure to diagnose)
     *
     * @ORM\Column(type="string", length=255)
     * @Serializer\Groups({"ADMIN", "API"})
     */
    private $title;

    /**
     * @ORM\OneToOne(targetEntity="App\Entity\Node")
     * @ORM\JoinColumn(referencedColumnName="id")
     *
     * @Serializer\Groups({"ADMIN"})
     */
    private $firstNode;

    public function getId()
    {
        return $this->id;
    }


    public function getTitle(): ?string
    {
        return $this->title;
    }

    public function setTitle(string $title): self
    {
        $this->title = $title;
        return $this;
    }

    public function getFirstNode(): ?Node
    {
        return $this->firstNode;
    }

    public function setFirstNode(?Node $firstNode): self
    {
        $this->firstNode = $firstNode;
        return $this;
    }
}

As you see, I've created two exclusion groups so that I can hide or expose the properties I want. That works great!

But for the properties inside the node to be visible, I have to add the @Serializer\Groups annotations for all the properties, and propagate it to the classes of the properties all down along the dependencies.

I would like not to have to copy the @Serializer\Groups annotations in all of my entity classes. So I tried with JMS Exclusion policies (@Serializer\ExclusionPolicy()), but this does not seem to work.

Is there a way to expose/exclude a class, inconditionnaly of the current JMS exclusion group ? Thanks.


Solution

  • After 24 hours, I realised that I misused the concept of exclusion groups for jms serializer.

    • Before: I had 2 groups : "API" and "ADMIN". With this organisation, I needed to declare every property in the groups, and this, all along my dependency tree (like for a white list).
    • Now: I only have one group "ADMIN". With this organisation, I need:
      • to declare in the group "ADMIN", only the properties that are not publicly visible
      • to declare my controllers for the group "Default" for the public requests, and for the groups "ADMIN" and "Defaults" for the requests that are admin-only. I don't need to propagate any exclusion groups down the dependency tree.

    This resolves my problem nicely. But maybe my initial demand is still legit.