使用JMSSerializer进行Symfony 4 FOSRestBundle序列化

时间:2018-04-23 13:47:50

标签: php symfony symfony4 fosrestbundle jms-serializer

我正在使用Symfony 4和FOSRestBundle构建API。我有很基本的关系:

实体: User.php

/**
* @ORM\Entity(repositoryClass="App\Repository\UserRepository")
*/
class User
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @JMS\Groups({"onlyId"})
     */
    private $id;

    /**
     * @ORM\Column(unique=true, type="string", length=255)
     */
    private $email;

    //...

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\UserProduct", mappedBy="user", orphanRemoval=true)
     */
    private $userProducts;

实体: UserProduct.php

/**
* @ORM\Entity(repositoryClass="App\Repository\UserProductRepository")
*/
class UserProduct
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     * @JMS\Groups({"onlyId"})
     */
    private $id;

    //...

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="userProducts")
     * @JMS\Groups({"onlyId"})
     */
    private $user;

配置: fos_rest.yaml

fos_rest:
    body_converter:
        enabled: true
    view:
        view_response_listener: 'force'
        formats:
            json: true
    routing_loader:
        default_format: json
#    param_fetcher_listener:  true
#    allowed_methods_listener:  true
#    routing_loader: true
#    view:
#        view_response_listener:  true
#    exception:
#        codes:
#            App\Exception\MyException: 403
#        messages:
#            App\Exception\MyException: Forbidden area.
    format_listener:
        rules:
            - { path: ^/api, prefer_extension: true, fallback_format: json, priorities: [ json, html ] }
            - { path: ^/login_check, stop: true }
            - { path: ^/register, stop: true }

首先,当我发布用户ID和JSON数据时,我无法 POST UserProduct将JSON发送到端点,因为它正在抛出它期望{{1}的实例},而不是entity或我发送的任何内容。我用这个教程想出来了 - > https://medium.com/@maartendeboer/using-the-symfony-serializer-with-doctrine-relations-69ecb17e6ebd

它使用Symfony Serializer。返回integer FOSRestBundle时,我得到的是circular reference错误。在这一点上,我知道使用JMS Serializer工具可以很好地处理View错误,并在我的circular reference控制器中使用它:

发布产品并处理postUserProductAction我使用此控制器(使用自定义编写的反序列化方法反序列化已发布的JSON,将其导入数据库,然后返回响应(不是View)在JMS Serializer及其小组的帮助下:

circular reference

我得到的回应很好而且很明确:

class UserProductController extends FOSRestController
    {
    /**
     * @Rest\Route("/api/product", name="userProduct")
     *
     *
     * @Method("POST")
     *
     * @param Request $request
     * @param SerializerInterface $serializer
     * @return Response
     * @throws \InvalidArgumentException
     */
    public function postUserProductAction(Request $request, SerializerInterface $serializer): View
    {
        $userProduct = $serializer->deserialize($request->getContent(), UserProduct::class, 'json');
        dump($userProduct);
        $em = $this->getDoctrine()->getManager();
        $em->persist($userProduct);
        $em->flush();

        $userProduct = $this->JMSSerializeWithGroups($userProduct,array('onlyId'));
        return new View($userProduct, Response::HTTP_OK);
    }
}

    /**
     * @param $entity
     * @param array $groupArray
     * @return mixed|string
     */
    public function JMSSerializeWithGroups($entity, Array $groupArray)
    {
        $JMSserializer = SerializerBuilder::create()->build();
        $entity = $JMSserializer->serialize( $entity, 'json', SerializationContext::create()->setGroups($groupArray));
        return $entity;
    }

但似乎有很多不必要的步骤。另外,如果我选择这种方法,我需要自己将JMS序列化添加到我的每个控制器(GET,PUT等)。

所以我的问题为什么FOSRestBundle默认不使用JMS来渲染{ "id": 100, "user": { "id": 9 } } ,因为它说它应该在他们的文档中(如果已安装并注册)?除了FOSRestBundle之外,我应该在某处添加它来识别吗?也许如果可以的话,我不需要首先使用Symfony Serializer?我想我可能会在所有Symfony 4升级中迷失。

谢谢!

1 个答案:

答案 0 :(得分:0)

由于我没有得到任何建议,我坚持使用我发布的相同解决方案。我会留下它,万一有人需要它,因为它是完全有效的例子。

干杯