【问题标题】:Symfony - Doctrine : Designing REST api for receiving Many To Many EntitiesSymfony - Doctrine : 设计用于接收多对多实体的 REST api
【发布时间】:2018-01-05 16:20:18
【问题描述】:

假设我有两个 ORM 实体:

作者实体:

<?php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(
 *        name="authors",
 *        uniqueConstraints={@ORM\UniqueConstraint(name="date", columns={"author_id"})}
 * )
 */
class Author implements \JsonSerializable
{

 /**
 * @var integer
 *
 * @ORM\Column(type="integer", nullable=false)
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="IDENTITY")
 */
public $id;

/**
 * @var string
 * @ORM\Column(type="string", length=250, nullable=true)
 */
public $name;

/**
 *
 * Many Authors have Many Books.
 * @ORM\ManyToMany(targetEntity="Book")
 * @ORM\JoinTable(name="authors_books",
 *      joinColumns={@ORM\JoinColumn(name="author_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="book_id", referencedColumnName="id")}
 *      )
 */
public $books;


public function __construct(User $user, \DateTime $startDate, \DateTime $ringDate, $phone, $name, $direction, $duration, $comment, $phoneId, $appVersion)
{
    $this->name = $name;
    $this->books = new \Doctrine\Common\Collections\ArrayCollection();

}

public function jsonSerialize()
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'books' => $this->books,
    ];
}
}

图书实体:

<?php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="books")
 * @ORM\Entity()
 */
class Book implements \JsonSerializable
{
    /**
     * @var integer
     *
     * @ORM\Column(type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    public $id;

    /**
     * @var string
     * @ORM\Column(type="string", length=120, nullable=false)
     */
    public $description;

    /**
     * @var string
     * @ORM\Column(type="string", length=10)
     */
    public $color;

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

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

    public function getdecription()
    {
        return $this->decription;
    }

    public function setDecription($decription)
    {
        $this->decription = $decription;
    }

    function jsonSerialize()
    {
        return [
            'id' => $this->id,
            'decription' => $this->decription,
        ];
    }
}

作为这种关系的结果,生成了 authors_books 表。 我现在的目标是设计一个控制器,它会在以下json format 示例中返回作者列表:

{
    authors: [
        {
            name: "Oscar Wilde",
            books : [
                {
                    id: 1,
                    description: "The Picture of Dorian Gray"
                },
                {
                    id: 2,
                    description: "The Happy Prince and Other Tales"
                }
            ]
        },
        {
            name: "Charles Dickens",
            books : [
                {
                    id: 3,
                    description: "Great Expectations"
                },
                {
                    id: 4,
                    description: "Oliver Twist"
                }
            ]
        }
        ]
}

使用像这样的休息控制器:

/**
 * @Route("/my/v1", service="app.authors_controller")
 */
class MyController extends BaseApiController
{

    /**
     * @Route("/authors", name="my_v1_authors")
     * @Method("GET")
     */
    public function authors(Request $request)
    {

        $qb = $this->authorRepository->createQueryBuilder('c');

        return new JsonResponse(array(
            'authors' => ...
        ));
    }
}

就目前而言,我有两个实现这一目标的想法:

  1. 执行两个请求:一个请求一组作者,另一个请求一组书籍。
  2. 将书籍实体数组的 json 表示形式保留为附加作者表的列。

但在我看来,他们俩都有些老套。我该怎么办?

请注意,这是我想要实现的目标的简化表示。尽管在这个特定示例中使用多对多关系似乎是一种开销,但它对我当前的任务至关重要。

【问题讨论】:

  • 您不能编写一个自定义存储库函数来获取作者和底层图书实体,然后配置一个序列化方法来返回该数据吗?
  • 查看 JMS 序列化程序。它可以根据您的配置序列化集合和所有相关的对象/集合。 jmsyst.com/bundles/JMSSerializerBundle

标签: php symfony doctrine-orm orm


【解决方案1】:

你如何在你的作者实体中更改你的 JsonSerialize

public function jsonSerialize()
{
    $author = [
        'id' => $this->id,
        'name' => $this->name,
        'books' => []
    ];

    foreach($this->books as $book)
    {
        $author['books'][] = $book->jsonSerialize();
    }

    return $author;
}

在你的控制器中:

$authors = /** your optimized query here **/
$serializedAuthors = [];

foreach($authors as $author)
{
    $serializedAuthors[] = $author->jsonSerialize();
}

如果你可能重用这个逻辑,你可以考虑使用 symfony 的 Serializer 组件,一个很好的指南可以在这里找到https://thomas.jarrand.fr/blog/serialization/

或者也许使用 JMSSerializer。

编辑

您的 DQL 可能如下所示:

$authors = $this->getEntityManager()->createQuery('
    SELECT author, books
    FROM AppBundle\Entity\Author author
    JOIN author.books books
')->getResult();

【讨论】:

  • 我只是不明白这是如何工作的:我正在使用来自authors 表的作者的本机 sql 查询结果获取。是否假设学说会为每个对应的author 实体在幕后获取books
  • 是的,或者如果您更喜欢一次性加载它,您可以为此编写自定义 DQL,而不是原始查询。检查我的编辑
  • 感谢您的回复,这正是我想要的!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多