Как решить проблему с вложенными отношениями onetomany, не отображаемыми в маршруте Apigility - PullRequest
2 голосов
/ 11 апреля 2019

У меня проблема с использованием Apigility и Doctrine в их последних версиях.

У меня есть 2 объекта: реклама и приложение на двусторонних отношениях. Многие приложения могут быть связаны с рекламой, а у рекламы много приложений. Мои таблицы созданы как таковые (внешний ключ advert_id в таблице приложений).

Мне не удается вызвать маршрут объявления с его приложениями, поле приложений всегда пусто.

После некоторых исследований я пришел к выводу, что apigility просто не знает, как отобразить вложенную коллекцию. Я читал о гидраторах и пакете api-skeletons / zf-doctrine-hydrator, который обеспечивал бы помощника для этих вложенных отношений доктрины, но, к сожалению, он не совместим с версией 4 phpro / zf-doctrine-hydration-module, и я не могу понизить из-за других пакетов и зависимостей.

<?php

namespace Fil\V1\Entity;

use Doctrine\ORM\Mapping as ORM;

class Applications
{
    /**
     * @var \Fil\V1\Entity\Adverts
     *
     * @ORM\ManyToOne(targetEntity="Fil\V1\Entity\Adverts",inversedBy="applications")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="author_id", referencedColumnName="id", nullable=true)
     * })
     */
    private $advert;

    /**
     * Set advert.
     *
     * @param \Fil\V1\Entity\Adverts|null $advert
     *
     * @return Applications
     */
    public function setAdvert(\Fil\V1\Entity\Adverts $advert = null)
    {
        $this->advert = $advert;

        return $this;
    }

    /**
     * Get advert.
     *
     * @return \Fil\V1\Entity\Adverts|null
     */
    public function getAdvert()
    {
        return $this->advert;
    }
}
class Adverts
{
   ...
    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\OneToMany(targetEntity="Fil\V1\Entity\Applications", mappedBy="advert")
     */
    private $applications;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->applications = new \Doctrine\Common\Collections\ArrayCollection;
    }

    /**
     * Add application.
     *
     * @param \Fil\V1\Entity\Applications $application
     *
     * @return Adverts
     */
    public function addApplication(\Fil\V1\Entity\Applications $application)
    {
        $this->applications[] = $application;

        return $this;
    }

    /**
     * Remove application.
     *
     * @param \Fil\V1\Entity\Applications $application
     *
     * @return boolean TRUE if this collection contained the specified element, FALSE otherwise.
     */
    public function removeApplication(\Fil\V1\Entity\Applications $application)
    {
        return $this->applications->removeElement($application);
    }

    /**
     * Get applications.
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getApplications()
    {
        return ($this->applications);
    }
}

Когда я вызываю маршрут для Приложений (пример: Applications / 1), он работает отлично, я получаю свой объект json с правильной связью Advert со всей информацией. Так что отношения хорошо продуманы. {

id: 2,
name: "application1",
_embedded: 
    {
      advert: 
           {
            id: 1,
            name: "Advert1",
            applications: { },
            _links: 
              {
               self: 
                  {
                   href: "http://localhost:8080/adverts/1"
                   }
              }
    }
 }, 
 _links: 
    {
      self: 
         {
         href: "http://localhost:8080/applications/2"
         }
    }
}

Проблема в том, когда я звоню и рекламирую маршрут (пример: реклама / 2). Я получаю Json с правильной рекламной информацией, но поле приложений пусто, просто {}. Есть несколько приложений, связанных с рекламой, но она просто не работает.

{
    id: 2,
    name: "Advert1,
    applications: { },
    _links: 
       {
          self: 
             {
                href: "http://localhost:8080/adverts/2"
              }
        }
}

Обычно поле приложений должно быть заполнено различными объектами, представляющими каждое из приложений.

Есть ли способ преодолеть эту проблему? спасибо!

1 Ответ

0 голосов
/ 13 апреля 2019

Пакет поставщика ApiSkeletons имеет это в соответствии с дизайном. Я с вами, предпочел бы вернуть коллекции, но исправить это легко: создайте новую стратегию!

  • Создайте класс стратегии и расширьте AllowRemoveByValue стратегию Доктрины.
  • Перезаписать функцию extract, чтобы вернуть коллекцию, заполненную или пустую

Вот и все.

Полный класс:

namespace Application\Strategy;

use DoctrineModule\Stdlib\Hydrator\Strategy\AllowRemoveByValue;
use ZF\Hal\Collection;

class UniDirectionalToManyStrategy extends AllowRemoveByValue
{
    public function extract($value)
    {
        return new Collection($value ?: []);
    }
}

Применяйте эту стратегию там, где вам это нужно. Например. ваш Advert столько же Applications, поэтому конфиг должен быть изменен так:

'doctrine-hydrator' => [
    'Fil\\V1\\Entity\\ApplicationHydrator' => [
        // other config
        'strategies' => [
            'adverts' => \Application\Strategy\UniDirectionalToManyStrategy::class,
        ],
    ],
],

Теперь коллекции должны быть возвращены.


Краткое примечание: это будет работать только как стратегия для стороны * ToMany .

...