JMS Serializer: How to limit the depth of serialisation for an object graph

11,685

Solution 1

Because I did not have access to the latest version of the serializer I had to find a workaround to the @MaxDepth. This may also help you.

Use @JMS\ExclusionPolicy("all") on all entities that are connected.

Now use @JMS\Expose only on those properties that you want to have serialize. On join relations only use this annotation in one direction. That will fix your problem.

namespace FinalConcept\TimeTracker\EntitiesBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as JMS;

/**
 * FinalConcept\TimeTracker\EntitiesBundle\Entity
 *
 * @JMS\ExclusionPolicy("all")
 * @ORM\Table(name="users")
 * @ORM\Entity(repositoryClass="FinalConcept\TimeTracker\EntitiesBundle\Repository\UserRepository")
 */
class User implements UserInterface, \Serializable
{
     /**
     * @JMS\Expose
     * @ORM\ManyToOne(targetEntity="company", inversedBy="users")
     * @ORM\JoinColumn(name="company_id", referencedColumnName="id")
     */
    private $company;
}

Solution 2

As of the latest version, using @MaxDepth() annotation and SerializationContext::create()->enableMaxDepthChecks() in the controller does the job.

Share:
11,685
concept
Author by

concept

Updated on July 10, 2022

Comments

  • concept
    concept almost 2 years

    Maybe it is just my misunderstanding of this annotation however it does not seam to work as expected.

    I have the following object graph

    User
     -> Company
      -> Users
       -> Groups
        -> Permissions
    

    As you can see there will be some recursion. JMS handles this quite well by not serialising the other user's company properties as well as not the current user.

    However I want the serialization to stop at and include company.

    I have tried this expecting that once the level $context->level = 2 it would stop

    <?php
    namespace FinalConcept\TimeTracker\EntitiesBundle\Entity;
    
    use Doctrine\Common\Collections\ArrayCollection;
    use Doctrine\ORM\Mapping as ORM;
    use JMS\Serializer\Annotation as JMS;
    
    /**
     * FinalConcept\TimeTracker\EntitiesBundle\Entity
     *
     * @ORM\Table(name="users")
     * @ORM\Entity(repositoryClass="FinalConcept\TimeTracker\EntitiesBundle\Repository\UserRepository")
     */
    class User implements UserInterface, \Serializable
    {
         /**
         * @ORM\ManyToOne(targetEntity="company", inversedBy="users")
         * @ORM\JoinColumn(name="company_id", referencedColumnName="id")
         * @JMS\MaxDepth(depth=1)
         */
        private $company;
    }
    

    However this is not the case. Even stepping through the code has not shed any light on how to stop this.

    I am happy to create a custom handler if I can only invoke it for a specific path i.e. User.Company

    I also need this for User.Groups which has the following graph

    User
     -> Groups
      -> Permissions
     -> Users
       -> Groups
         -> users ....
    

    Thanks in advance for any help how to limit the depth of serialization for an object graph

  • famas23
    famas23 almost 6 years
    Hey thank you for your amazing response. is it possible to mention @MaxDepth on the hole class??
  • Alexandru Cosoi
    Alexandru Cosoi almost 6 years
    No sry. @MaxDepth is marked as property/Method annontation @Target({"PROPERTY","METHOD"})