Symfony ManyToMany设置器返回错误数据

时间:2019-04-06 12:24:35

标签: php symfony doctrine many-to-many

我与Coupon ManyToMany有关系。 用户有许多优惠券,并且优惠券可能属于许多用户。 当我调用方法$ coupon-> getUsers()时,我得到了优惠券(PersistentCollection)。 当我调用方法$ user-> getCoupon()时,我得到了用户(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;
    }
}

我得到: screenshot

为什么我得到优惠券而不是用户列表?

2 个答案:

答案 0 :(得分:1)

除了Jakumi所写的内容之外,您还可以在控制器中执行

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

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

现在,当您dump($users)时集合不应为空。

此外,我认为您的映射错误。在您的多对多关系中,User是拥有方,而Coupon是相反方,但是public function addUser(User $user)实体中的Coupon是{ {3}}。您应该更改边(将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;
}

当然,应该相应地处理removeUserremoveCoupon方法。

答案 1 :(得分:0)

PersistentCollection从概念上讲应该像数组一样工作,并且是实现延迟加载(默认)的原则。有某些操作将触发从数据库加载集合(例如遍历集合)。在此之前,它的属性initialized将为false(如您的屏幕截图所示)

ManyToMany和OneToMany应该始终实现为ArrayCollection(或某些其他集合,例如PersistentCollection),并且不应泄漏到外部。而是调用->toArray()(或我经常忘记的->asArray())来返回它们(因此,分别在getUsers()getCoupons()内部)。在实体内部,您可以foreach上方的PersistentCollection上。

如果将ManyToMany标记为fetchEAGER,它将立即被加载,但这可能会影响性能...

并且Collection拥有对其所属对象的引用,因此您本身并没有得到Coupon,而是获得了一个仍引用其所有者; o)