使用id(不是IRI)在ManyToMany关系中的API平台POST嵌入式文档

时间:2020-11-03 11:13:41

标签: php symfony doctrine-orm doctrine api-platform.com

我有2个实体,BlogPost和Category,这具有多对多关系。为了发出发布请求,我想为BlogPost发出发布请求时,是否可以仅引用实体的ID(在本例中为category_id)?

使用IRI参考有效

{
  "title": "Post new",
  "createdAt": "2020-11-03T11:03:04.930Z",
  "excerpt": "Excerpt doc",
  "content": "Content doc",
  "slug": "post-new",
  "categories": [
    {"/api/categories/1"},
    {"/api/categories/2"}
  ],
  "thumbnail": "string"
}

但是这样的模式,仍然有问题

{
  "title": "Post new",
  "createdAt": "2020-11-03T11:03:04.930Z",
  "excerpt": "Excerpt doc",
  "content": "Content doc",
  "slug": "post-new",
  "categories": [
    {"id": 1},
    {"id": 2}
  ],
  "thumbnail": "string"
}

这是我的 BlogPost 实体:

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\BlogPostRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ApiResource(
 *     itemOperations={
 *          "get",
 *          "put",
 *          "delete"
 *      },
 *     collectionOperations={
 *          "get",
 *          "post"
 *      },
 *     normalizationContext={
 *          "groups"={"blogpost:read"}
 *      },
 *     denormalizationContext={
 *          "groups"={"blogpost:write"}
 *      },
 *     shortName="posts"
 * )
 * @ORM\Entity(repositoryClass=BlogPostRepository::class)
 */
class BlogPost
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"blogpost:read", "blogpost:write"})
     * @Assert\NotBlank()
     */
    private $title;

    /**
     * @ORM\Column(type="datetime")
     * @Groups({"blogpost:read", "blogpost:write"})
     */
    private $createdAt;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     * @Groups({"blogpost:read", "blogpost:write"})
     */
    private $excerpt;

    /**
     * @ORM\Column(type="text")
     * @Groups({"blogpost:read", "blogpost:write"})
     */
    private $content;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups({"blogpost:read", "blogpost:write"})
     */
    private $slug;

    /**
     * @ORM\ManyToMany(targetEntity=Category::class, inversedBy="post", cascade={"persist"})
     * @Groups({"blogpost:read", "blogpost:write"})
     */
    private $categories;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     * @Groups({"blogpost:read", "blogpost:write"})
     */
    private $thumbnail;

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

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

    public function getTitle(): ?string
    {
        return $this->title;
    }

    public function setTitle(string $title): self
    {
        $this->title = $title;

        return $this;
    }

    public function getCreatedAt(): ?\DateTimeInterface
    {
        return $this->createdAt;
    }

    public function setCreatedAt(\DateTimeInterface $createdAt): self
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    public function getExcerpt(): ?string
    {
        return $this->excerpt;
    }

    public function setExcerpt(?string $excerpt): self
    {
        $this->excerpt = $excerpt;

        return $this;
    }

    public function getContent(): ?string
    {
        return $this->content;
    }

    public function setContent(string $content): self
    {
        $this->content = $content;

        return $this;
    }

    public function getSlug(): ?string
    {
        return $this->slug;
    }

    public function setSlug(string $slug): self
    {
        $this->slug = $slug;

        return $this;
    }

    /**
     * @return Collection|Category[]
     */
    public function getCategories(): Collection
    {
        return $this->categories;
    }

    public function addCategory(Category $category): self
    {
        if (!$this->categories->contains($category)) {
            $this->categories[] = $category;
        }

        return $this;
    }

    public function removeCategory(Category $category): self
    {
        if ($this->categories->contains($category)) {
            $this->categories->removeElement($category);
        }

        return $this;
    }

    public function getThumbnail(): ?string
    {
        return $this->thumbnail;
    }

    public function setThumbnail(?string $thumbnail): self
    {
        $this->thumbnail = $thumbnail;

        return $this;
    }
}

这是我的类别实体

<?php

namespace App\Entity;

use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\CategoryRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * @ApiResource(
 *     itemOperations={"get", "delete", "put"},
 *     collectionOperations={"get", "post"},
 *     normalizationContext={"groups"={"category:read"}},
 *     denormalizationContext={"groups"={"category:write"}},
 * )
 * @ORM\Entity(repositoryClass=CategoryRepository::class)
 */
class Category
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Groups({"category:read"})
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=50)
     * @Groups({
     *      "category:read",
     *      "category:write"
     * })
     */
    private $name;

    /**
     * @ORM\Column(type="string", length=50)
     * @Groups({
     *      "category:read",
     *      "category:write"
     * })
     */
    private $slug;

    /**
     * @ORM\ManyToMany(targetEntity=BlogPost::class, mappedBy="categories")
     * @Groups({"category:read", "blogpost:write"})
     */
    private $post;

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

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

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

    public function setName(string $name): self
    {
        $this->name = $name;

        return $this;
    }

    public function getSlug(): ?string
    {
        return $this->slug;
    }

    public function setSlug(string $slug): self
    {
        $this->slug = $slug;

        return $this;
    }

    /**
     * @return Collection|BlogPost[]
     */
    public function getPost(): Collection
    {
        return $this->post;
    }

    public function addPost(BlogPost $post): self
    {
        if (!$this->post->contains($post)) {
            $this->post[] = $post;
            $post->addCategory($this);
        }

        return $this;
    }

    public function removePost(BlogPost $post): self
    {
        if ($this->post->contains($post)) {
            $this->post->removeElement($post);
            $post->removeCategory($this);
        }

        return $this;
    }
}

要实现这一目标的基本配置是什么?

谢谢。

3 个答案:

答案 0 :(得分:0)

只需使用序列化程序提供的组即可。

在要公开的每个属性上定义组“ BlogPost”(因此,对于您的Category实体,仅$ id) 然后,使用命名组调用规范化(或序列化,具体取决于您的需求):

advance()
{
 if (++base >= size)
    base = 0;
    int ptr = base + future;
    if (ptr >= (int)size)
        ptr -= size;
    (reinterpret_cast<T *>(index[ptr]))->~T();
    std::memset(index[ptr], 0, sizeof(T));
    new (index[ptr]) T;
}

答案 1 :(得分:0)

我认为您必须为此使用自定义控制器。

 *   collectionOperations={
 *          "post"={
 *              "method"="POST",
 *              "controller"=PostAdd::class,
 *          }
 *     }

了解更多详情 https://api-platform.com/docs/core/controllers/

答案 2 :(得分:0)

还不能发表评论,但我很确定帖子正文应该是

{
  "title": "Post new",
  "createdAt": "2020-11-03T11:03:04.930Z",
  "excerpt": "Excerpt doc",
  "content": "Content doc",
  "slug": "post-new",
  "categories": [
    "/api/categories/1",
    "/api/categories/2"
  ],
  "thumbnail": "string"
}