N
N
Nikita Gushchin2015-09-02 19:58:50
symfony
Nikita Gushchin, 2015-09-02 19:58:50

How to automatically load nested entities (ParamConverter)?

I use FOSRestBundle, JMSSerializerBundle. For a get request, the required entity is automatically loaded from the database:

/**
     * @param ProductCategory $slug
     * @return ProductCategory
     *
     * @Rest\Route(requirements={"slug" = "\d+"})
     * @Rest\View()
     */
    public function getAction(ProductCategory $slug)
    {
        return $slug;
    }

And for a post-request to add, we always have no id in the request body, but there is an id of nested entities (Image, for example).
How can I make nested entities with id set automatically loaded from the database?
/**
     * @param ProductCategory $category
     * @return ProductCategory
     *
     * @Rest\Route(path="")
     * @ParamConverter(
     *      name="category",
     *      converter="fos_rest.request_body",
     *      class="FiveToFive\ergil\DomainBundle\Entity\ProductCategory"
     * )
     * @Rest\View()
     */
    public function postAction(ProductCategory $category)
    {
        $categoryService = $this->get("product.category.service");
        return $categoryService->createNew($category);
    }

Request body example:
{
    "title": "My second post",
    "image": {
        "id": 20
    }
}

Entity example:
ProductCategory

/**
 * @ORM\Entity
 * @Serializer\ExclusionPolicy("ALL")
 */
class ProductCategory
{
    /**
     * @var integer
     *
     * @Assert\Blank(groups={"import"})
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     * @Serializer\Expose()
     */
    private $id;

    /**
     * @var string
     *
     * @Assert\NotBlank(groups={"import"})
     * @Assert\Length(max="250", groups={"import"})
     * @ORM\Column(type="string", unique=true, length=255, nullable=false)
     * @Serializer\Expose()
     */
    private $title;

    /**
     * @var Image
     *
     * @Assert\NotBlank(groups={"import"})
     * @Assert\Valid()
     * @ORM\OneToOne(targetEntity="FiveToFive\ergil\DomainBundle\Entity\Image", cascade={ "remove" })
     * @ORM\JoinColumn(name="image_id", referencedColumnName="id", unique=true)
     * @Serializer\Expose()
     */
    private $image;

    /**
     * @var ArrayCollection|Product
     *
     * @Assert\Valid()
     * @Assert\Collection\Optional()
     * @ORM\OneToMany(targetEntity="FiveToFive\ergil\DomainBundle\Entity\Product", mappedBy="category")
     */
    private $products;

    // ....
}

Answer the question

In order to leave comments, you need to log in

2 answer(s)
N
Nikita Gushchin, 2015-09-03
@iNikNik

As time went on, I suddenly realized that on top of that, the param converter DOES NOT call entity constructors AT ALL. Googling a bit found this (git issue) and this (stackoverflow) : if added to the services config:

services:
    # ...
    jms_serializer.object_constructor:
        alias: jms_serializer.doctrine_object_constructor
        public: false

Then the entities will be initialized as they should, and as a bonus, the param converter will still start loading nested entities. Of course, I found this in the documentation, but only now.

S
Sergey, 2015-09-02
Protko @Fesor

JmsSerializer can deserialize all this, and fos rest has the param converter you need.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question