如何在 Symfony 5 中创建用于序列化 json 的自定义 Normilizer? [英] How to create a custom Normilizer for serializing json in Symfony 5?

查看:49
本文介绍了如何在 Symfony 5 中创建用于序列化 json 的自定义 Normilizer?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用 symfony 创建一个 REST api 并最终想要返回一个自定义的 json.例如隐藏一些字段,从关系对象中获取特定字段(来自外键)等等(底部示例).

I am creating a REST api with symfony and ultimately want to return a custom json. For example hide some fields, get specific fields from the relation object (coming from the foreign key) and so on (example at the bottom).

我有两个具有 ManyToOne/OneToMany 关系的实体,Product &类别.

I have two entites with a ManyToOne/OneToMany relation, Product & Category.

Product.php:

<?php

namespace App\Entity;

use App\Repository\ProductRepository;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass=ProductRepository::class)
 */
class Product
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

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

    /**
     * @ORM\Column(type="text")
     */
    private $description;

    /**
     * @ORM\Column(type="float")
     */
    private $price;

    /**
     * @ORM\Column(type="boolean")
     */
    private $available;

    /**
     * @ORM\ManyToOne(targetEntity=Category::class, inversedBy="products")
     * @ORM\JoinColumn(nullable=false)
     */
    private $category;

    // ...
    // Rest of getters & setters
    // ...

    public function getCategory(): ?Category
    {
        return $this->category;
    }

    public function setCategory(?Category $category): self
    {
        $this->category = $category;

        return $this;
    }

Category.php:

<?php

namespace App\Entity;

use App\Repository\CategoryRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass=CategoryRepository::class)
 */
class Category
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

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

    /**
     * @ORM\OneToMany(targetEntity=Product::class, mappedBy="category")
     */
    private $products;

    public function __construct()
    {
        $this->products = new ArrayCollection();
    }

    // ...
    // Rest of getters & setters
    // ...

    /**
     * @return Collection|Product[]
     */
    public function getProducts(): Collection
    {
        return $this->products;
    }

    public function addProduct(Product $product): self
    {
        if (!$this->products->contains($product)) {
            $this->products[] = $product;
            $product->setCategory($this);
        }

        return $this;
    }

    public function removeProduct(Product $product): self
    {
        if ($this->products->removeElement($product)) {
            // set the owning side to null (unless already changed)
            if ($product->getCategory() === $this) {
                $product->setCategory(null);
            }
        }

        return $this;
    }

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

这是我的控制器:

class ProductApiController extends AbstractController
{
    /**
     * @Route("/products", name = "api_product_list")
     */
    public function getAll(SerializerInterface $serializer, ProductRepository $repo): Response
    {
        $products = $repo->findAll();
        $jsonObject = $serializer->serialize($products, 'json', [
            'circular_reference_handler' => function () {
                return null;
            }]
        );
        return new Response($jsonObject, 200, ['Content-Type' => 'application/json']);
    }
}

这是我当前的输出:

{
  "id": 1,
  "name": "Gaming pc",
  "description": "A nice computer",
  "price": 9800,
  "available": true,
  "category": {
    "id": 1,
    "name": "Computers",
    "products": [
      null
    ],
    "__initializer__": null,
    "__cloner__": null,
    "__isInitialized__": true
    }
}

这是我想要得到的输出:

This is the output I want to get:

{
  "id": 1,
  "name": "Gaming pc",
  "description": "A nice computer",
  "price": 9800,
  "available": true,
  "category": "Computers" // Basically this is why I need a custom serializer
}

这是文档 但我不知道该怎么办.

Here is the documentation but I couldn't figure out what to do in my case.

推荐答案

src/Serializer/ProductNormalizer.php 下:(路径需要准确,否则你将不得不 手动注册)

Under src/Serializer/ProductNormalizer.php: (The path needs to be exact, else you would have to register it manually)

<?php

namespace App\Serializer;

use App\Entity\Product;
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;

class ProductNormalizer implements ContextAwareNormalizerInterface
{
    private $normalizer;

    public function __construct(ObjectNormalizer $normalizer)
    {
        $this->normalizer = $normalizer;
    }

    public function normalize($product, string $format = null, array $context = [])
    {
        $data = $this->normalizer->normalize($product, $format, $context);
        $data = [
            'id' => $product->getId(),
            'name' => $product->getName(),
            'description' => $product->getDescription(),
            'price' => $product->getPrice(),
            'available' => $product->getAvailable(),
            'category' => $product->getCategory()->getName(), //Customize to your needs
        ];
        return $data;
    }

    public function supportsNormalization($data, string $format = null, array $context = [])
    {
        return $data instanceof product;
    }
}

这篇关于如何在 Symfony 5 中创建用于序列化 json 的自定义 Normilizer?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆