简体   繁体   中英

Symfony 3 FOS Rest + JMS Serializer groups

My composer.json (part of it):

{
    "require": {
        "symfony/symfony": "3.1.*",
        "jms/serializer-bundle": "^1.1",
        "friendsofsymfony/rest-bundle": "^2.1"
    }
}

I have some entities which I'd like to return partial data for the list action and complete for the find action. For so, I have these files:

Product.php

<?php

namespace AppBundle\Entity;

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

/**
* @ORM\Entity
* @ORM\Table(name="represented")
* @JMS\ExclusionPolicy("ALL")
*/
class Product
{
    /**
    * @var integer
    * @ORM\Column(type="integer", nullable=false, options={"unsigned"=true})
    * @ORM\Id
    * @ORM\GeneratedValue(strategy="AUTO")
    */
    protected $id;

    /**
    * @var string
    * @ORM\Column(type="string", nullable=false, length=48)
    */
    protected $name;

    /**
    * @var Group
    * @ORM\ManyToOne(targetEntity="Group", inversedBy="products")
    * @ORM\JoinColumn(name="group_id", referencedColumnName="id")
    */
    protected $group;

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

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setGroup(Group $group)
    {
        $this->group = $group;
    }

    public function getGroup()
    {
        return $this->group;
    }
}

ProductController.php

<?php

namespace AppBundle\Controller;

use FOS\RestBundle\Controller\Annotations\Get;
use FOS\RestBundle\Controller\FOSRestController;
use AppBundle\Entity\Product;

class ProductController extends FOSRestController
{
    /**
    * @Get("/product", name="list_products")
    */
    public function listAction()
    {
        $products = $this->getDoctrine()
            ->getRepository('AppBundle:Product')
            ->findBy([], [ 'name' => 'ASC' ]);

        $view = $this->view($products);

        return $this->handleView($view);
    }

    /**
    * @Get("/product/{id}", requirements={"id" = "\d+"}, name="get_product")
    */
    public function getAction($id)
    {
        $em = $this->getDoctrine()->getManager();

        $product = $em->getRepository('AppBundle:Product')
            ->find($id);

        if ( ! $product) {
            $error = [
                'error' => 'Product not found'
            ];

            $view = $this->view($error, 404);
        } else {
            $view = $this->view($product);
        }

        return $this->handleView($view);
    }
}

I would like to be able to not show the group property on the list result. For this I have tried a few of approaches, mainly with groups.

  1. Just use configure the group name for the properties I want to show on my list with Groups({"List"}) and refer this group on the controller with @View(serializerGroups={"List"}) . But this had no affect as all properties are visible.
  2. Configure @ExclusionPolicy("all") for the entire entity didn't work as well.
  3. In addition to ExclusionPolicy, @Expose to all properties I wanted to show in some or all groups, but that made all properties marked to be shown.

I also tried some more variants of these, but nothing that change the results.

End of your controller action should not be only:

return $this->handleView($view);

But for getting a group or groups working you need to activate them. On top of the class you need to add FOSRest Context, not JMS context:

use FOS\RestBundle\Context\Context;

and in the controller actions before returning view:

$view = $this->view($products, 200);
$context = new Context();
$context->setGroups(['list']);
$view->setContext($context);

return $this->handleView($view);

This will work for Symfony 3.2 and FOSRest 2.1 and 2.0.

Link for upgrading documentation for FOSRest: https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/UPGRADING-2.0.md

If you use @Exclude then this should work. Another option I have used is to make a small addition to config.yml :

fos_rest:
    serializer:
        groups: ['Default']

This requires that the entity properties be in the group Default in order to be serialized. If you have no @Groups annotation on a property then it will be in Default , but as soon as you add the @Groups annotation then it will no longer be in the Default group (unless you specifically add it.)

This allowed the default serialization process to include all the entity fields except for those with a @Groups annotation, and then elsewhere I could serialize with both Default and my other groups selected if I wanted everything to be included.

// Function in the Controller class
public function getAction(MyEntity $me) {
    // Use automatic serializer, only things in 'Default' group are included
    return $me;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM