在JSON中使用OneToMany关联中的教义集合数据

时间:2018-11-11 20:23:52

标签: php doctrine-orm doctrine

我已经看到了许多有关如何在实体之间建立OneToMany关联的示例。但是,关于如何从关联中输出数据,我还没有看到任何东西。 (例如转换为JSON或仅具有干净的数组)

因此,这是一些示例代码:

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
}

然后我们还有分支机构实体:

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
}

通过调用$result->jsonSerialize()来查询两个实体的整体效果很好,然后返回return new JsonResponse($result)返回以获取JSON对象。尽管查询分支机构具有预期的结果,但在输出中我会收到该分支机构以及相关的银行,但对Bank的查询不会返回相关的分支机构,而是显示为"branches": {}

我知道这是因为$branches是一个Collection,但是如何以使其成为最终JSON对象的一部分的方式输出呢?

我已经尝试过$this->branches->toArray(),但是这导致无法将其编码为JSON的对象数组,因此以错误结尾。

注意:$this->getBranches()的内容(对象)确实包含预期的分支,$this->branches->count()可以看到这些分支。但是如何以允许JsonSerializable创建JSON的方式到达它们?

根据要求,以下是中间件代码,具体取决于实体使用情况:

工厂用于创建处理程序所需的内容:

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);
    }
}

工厂调用处理程序:

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);
    }
}

处理程序返回JSON。

1 个答案:

答案 0 :(得分:1)

需要注意的重要一点是,在实现\JsonSerializable接口时,直接调用jsonSerialize()不会返回JSON,并且您也不会显式调用此方法。

如文档所述:

  

实现JsonSerializable的对象可以在用json_encode()进行编码时自定义其JSON表示形式。

实现此接口的目的是强制执行jsonSerialize()方法,该方法在将对象传递到json_encode()时在内部调用;例如:

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

此外,如果您还要序列化分支分支子实体,则需要:

  1. 对此实体实施\JsonSerializable(您已完成)
  2. Doctrine将以ArrayCollection对象的形式返回这些分支,其中包含所有子分支对象。为了确保json_encode()将其正确编码为JSON,您需要使用ArrayCollectiontoArray()转换为数组。

为了说明-(如您所指出的,您也实现了这一点):

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

这应按预期顺序化您的银行和相关分支机构实体。希望这会有所帮助:)