Сеттер Symfony ManyToMany возвращает неверные данные - PullRequest
1 голос
/ 06 апреля 2019

У меня есть отношение пользователя к купону ManyToMany.У пользователя много купонов, и купон может принадлежать многим пользователям.Когда я вызываю метод $ coupon-> getUsers (), я получаю купон (PersistentCollection).И когда я вызываю метод $ user-> getCoupon (), я получаю user (PersistentCollection).

Пользовательская сущность:

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Coupon", inversedBy="users")
     */
    private $coupon;

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

    /**
     * @return Collection|Coupon[]
     */
    public function getCoupon(): Collection
    {
        return $this->coupon;
    }

    public function addCoupon(Coupon $coupon): self
    {
        if (!$this->coupon->contains($coupon)) {
            $this->coupon[] = $coupon;
        }

        return $this;
    }

    public function removeCoupon(Coupon $coupon): self
    {
        if ($this->coupon->contains($coupon)) {
            $this->coupon->removeElement($coupon);
        }

        return $this;
    }

Купонная сущность:

    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\User", mappedBy="coupon")
     */
    private $users;

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

    /**
     * @return Collection|User[]
     */
    public function getUsers(): Collection
    {
        return $this->users;
    }

    public function addUser(User $user): self
    {
        if (!$this->users->contains($user)) {
            $this->users[] = $user;
            $user->addCoupon($this);
        }

        return $this;
    }

    public function removeUser(User $user): self
    {
        if ($this->users->contains($user)) {
            $this->users->removeElement($user);
            $user->removeCoupon($this);
        }

        return $this;
    }

Когда я запускаю этот код:

namespace App\Controller;

use App\Entity\Coupon;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class TestController extends AbstractController
{
    /**
     * @Route("/test", name="test")
     */
    public function index()
    {
        $coupon = $this->getDoctrine()->getRepository(Coupon::class)->find(1);

        dump($coupon->getUsers());die;
    }
}

Я получаю: снимок экрана

Почему я получаюкупон, а не список пользователей?

Ответы [ 2 ]

1 голос
/ 06 апреля 2019

Кроме того, что написал Jakumi, в контроллере вы также можете сделать

$coupon = $this->getDoctrine()->getRepository(Coupon::class)->find(1);

$users = $coupon->getUsers();
$users->initialize();

Теперь, когда вы dump($users), коллекция не должна быть пустой.

Чтобы добавить к этому,Я полагаю, у вас неверное отображение.В вашем отношении «многие ко многим» User является стороной-владельцем, а Coupon - обратной стороной, однако именно public function addUser(User $user) в сущности Coupon выполняет работу со стороны-владельца ,Вам следует либо изменить стороны (изменить mappedBy в Coupon на inversedBy и наоборот в User), либо убедиться, что User делает:

public function addCoupon(Coupon $coupon): self
{
    if (!$this->coupon->contains($coupon)) {
        $coupon->addUser($this);
        $this->coupon[] = $coupon;
    }

    return $this;
}

иCoupon делает:

public function addUser(User $user): self
{
    if (!$this->users->contains($user)) {
        $this->users[] = $user;
    }

    return $this;
}

Конечно, методы removeUser и removeCoupon должны быть сработаны соответственно.

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

PersistentCollection концептуально должны работать как массивы и являются способом доктрины для реализации отложенной загрузки (по умолчанию).Существуют определенные операции, которые инициируют загрузку коллекции из базы данных (например, итерацию по коллекции).До этого его свойство initialized будет иметь значение false (как на вашем скриншоте)

ManyToMany и OneToMany всегда должны быть реализованы как ArrayCollection (или некоторая другая коллекция, например PersistentCollection) и не должны просачиваться наружу,Вместо этого вызовите ->toArray() (или ->asArray(), я всегда забываю), чтобы вернуть их (так, внутри getUsers() или getCoupons() соответственно).Внутри сущности вы можете просто foreach над PersistentCollection.

. Если пометить ManyToMany на fetch как EAGER, он будет загружен немедленно, но это может повлиять на производительность ...

И Коллекция содержит ссылку на объект, которому она принадлежит, поэтому вы не получаете купон как таковой, вы получаете коллекцию, которая по-прежнему ссылается на ее владельца; o)

...