简体   繁体   English

在 JSON 中使用来自 OneToMany 关联的 Doctrine Collection 数据

[英]Using data of Doctrine Collection from OneToMany association in JSON

I've seen many examples of how to set up a OneToMany association between Entities.我看过很多关于如何在实体之间建立 OneToMany 关联的例子。 However, I have not seen anything on how to output the data from an association.但是,我还没有看到有关如何从关联输出数据的任何信息。 (such as converting to JSON or just having a clean array) (例如转换为 JSON 或只是拥有一个干净的数组)

So, here is some sample code:所以,这里有一些示例代码:

declare(strict_types=1);

namespace Banks\Entity;

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

/**
 * https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/basic-mapping.html
 *
 * @ORM\Entity
 * @ORM\Table(name="bank")
 **/
class Banks implements \JsonSerializable
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer", name="id", nullable=false)
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;

    /**
     * A Bank could have Many Branches
     *
     * @ORM\OneToMany(targetEntity="Branches\Entity\Branches", mappedBy="bank")
     *
     */
    protected $branches;

    /**
     * @ORM\Column(type="string", nullable=true)
     */
    protected $name;

    /**
     *
     * @return array|mixed
     */
    public function jsonSerialize()
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'branches' => $this->getBranches()
        ];
    }

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

    public function getBranches(): Collection
    {
        return $this->branches;
    }

    // ... Other getter/setters removed
}

Then we also have the Branches Entity:然后我们还有分支实体:

declare(strict_types=1);

namespace Branches\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/basic-mapping.html
 *
 * @ORM\Entity
 * @ORM\Table(name="branches")
 **/
class Branches implements \JsonSerializable
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer", nullable=false)
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;

    /**
     * A Branch has one Bank
     *
     * @ORM\ManyToOne(targetEntity="Banks\Entity\Banks", inversedBy="branches")
     * @ORM\JoinColumn(name="bank_id", referencedColumnName="id")
     */
    protected $bank;

    /**
     * @ORM\Column(type="integer", nullable=false)
     */
    protected $bank_id;

    /**
     * @ORM\Column(type="string", nullable=true)
     */
    protected $name;

    /**
     *
     * @return array|mixed
     */
    public function jsonSerialize()
    {
        return [
            'id' => $this->id,
            'bank_id' => $this->bank_id,
            'name' => $this->name,
            'bank' => $this->getBank()
        ];
    }

    public function getBank()
    {
        return $this->bank;
    }

    // ... Other getter/setters removed
}

Querying both Entities work fine overall, with calls to $result->jsonSerialize() , then returning with return new JsonResponse($result) to get a JSON object.查询两个实体总体上工作正常,调用$result->jsonSerialize() ,然后返回return new JsonResponse($result)以获取 JSON 对象。 Though querying a Branch has the expected result, where I receive the Branch along with the associated Bank as part of the output, the query to Bank is not returning the associated Branches and instead only displays as "branches": {}虽然查询分支有预期的结果,我在其中收到分支以及关联的银行作为输出的一部分,但对银行的查询不会返回关联的分支,而是仅显示为"branches": {}

I know this is because $branches is a Collection, but how to output it in a way to be part of the resulting JSON object?我知道这是因为$branches是一个集合,但是如何以某种方式输出它以成为结果 JSON 对象的一部分?

I've tried $this->branches->toArray() , but that results in an array of Objects that cannot be encoded to JSON, therefore, ending in an error.我试过$this->branches->toArray() ,但这会导致无法编码为 JSON 的对象数组,因此以错误结尾。

NOTE: The contents (Object) of $this->getBranches() does contain the Branches as expected, which can be seen by $this->branches->count() .注意: $this->getBranches()的内容(对象)确实包含预期的分支,可以通过$this->branches->count()看到。 But how to reach them in such a way to allow JsonSerializable to create the JSON?但是如何以允许 JsonSerializable 创建 JSON 的方式访问它们?

As requested, here is middleware code leaving up to Entity usage:根据要求,这里是留给实体使用的中间件代码:

A factory is used to create what is needed by the Handler:工厂用于创建处理程序所需的内容:

class BanksViewHandlerFactory
{
    public function __invoke(ContainerInterface $container) : BanksViewHandler
    {
        $entityManager = $container->get(EntityManager::class);

        $entityManager->getConfiguration()->addEntityNamespace('Banks', 'Banks\Entity');

        $entityRepository = $entityManager->getRepository('Banks:Banks');

        return new BanksViewHandler($entityManager, $entityRepository);
    }
}

The Factory calls the Handler:工厂调用处理程序:

class BanksViewHandler implements RequestHandlerInterface
{
    protected $entityManager;
    protected $entityRepository;

    public function __construct(
        EntityManager $entityManager,
        EntityRepository $entityRepository,
    ) {
        $this->entityManager = $entityManager;
        $this->entityRepository = $entityRepository;
    }

    public function handle(ServerRequestInterface $request) : ResponseInterface
    {
        $return = $this->entityRepository->find($request->getAttribute('id'));

$result['Result']['Banks'] = $return->jsonSerialize();

        return new JsonResponse($result);
    }
}

The handler returns the JSON.处理程序返回 JSON。

It's important to note that, when implementing the \\JsonSerializable interface, calling jsonSerialize() directly does not return JSON, and you do not call this method explicitly.需要注意的是,在实现\\JsonSerializable接口时,直接调用jsonSerialize()不会返回JSON,也没有显式调用该方法。

As stated in the docs:如文档中所述:

Objects implementing JsonSerializable can customize their JSON representation when encoded with json_encode().使用 json_encode() 编码时,实现 JsonSerializable 的对象可以自定义其 JSON 表示。

The intent of implementing this interface is to enforce the jsonSerialize() method, which is called internally when passing the object(s) to json_encode() ;实现此接口的目的是强制执行jsonSerialize()方法,该方法在将对象传递给json_encode()时在内部调用; eg:例如:

$result = $banksRepository->find($id);
$json = json_encode($result);

Additionally, if you want to serialize the child Branch entities as well you need to:此外,如果您还想序列化子分支实体,您需要:

  1. Implement \\JsonSerializable for this entity (which you have done)为这个实体实现\\JsonSerializable (你已经完成了)
  2. Doctrine will return these Branches as an ArrayCollection object, containing all child Branch objects. Doctrine 将这些 Branches 作为ArrayCollection对象返回,包含所有子 Branch 对象。 In order to ensure that json_encode() encodes these to JSON properly you need to convert the ArrayCollection to an array using toArray() .为了确保json_encode()将这些正确编码为 JSON,您需要使用toArray()ArrayCollection转换为数组。

To illustrate - (as you pointed out you also implemented this):为了说明 - (正如你所指出的,你也实现了这一点):

public function jsonSerialize()
{
    return [
        'id' => $this->id,
        'name' => $this->name,
        'branches' => $this->getBranches()->toArray(), // <-- 
    ];
}

This should serialise your Bank and associated Branch entities as expected.这应该按预期序列化您的银行和关联的分行实体。 Hope this helps :)希望这可以帮助 :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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