symfony 3.4-ManyToOne无法访问实体的数据

时间:2018-11-30 15:36:03

标签: php symfony doctrine symfony-3.4

我有一个实体调用Category,另一个调用Product,中间一个名为CategoryProduct。

  • 我在Category和CategoryProduct之间有一个OneToMany关系: @ORM\OneToMany(targetEntity="CategoryProduct", mappedBy="Catego", fetch="EAGER")在CategoryProduct类中(在$ catego上)具有反dBy。
  • 我在CategoryProduct和Product:@ORM\OneToOne(targetEntity="Product", inversedBy="Category")之间具有一个OneToOne关系,在Product类中(在$ category上)具有inversedBy。

在我的CategoryController里面,我有一个像这样的函数:

public function getCategoryAction(Request $request)
{
    $category = $this->get('doctrine.orm.entity_manager')
                 ->getRepository('AppBundle:Category')
                 ->findAll();
    return new JsonResponse($category);
}

返回给出实体类别的集合,但是“子实体”产品为空。当我在Symfony中检查用于调试的Token时,我在“ Doctrine”部分中进行了检查,并且查询工作正常,数据已加载,但返回时不在这里。我可以使用$category->getProduct()访问数据(它为我提供了所需的指向类别的Product链接的集合),但我的Product子类仍然为空。有人知道为什么吗?

感谢您的帮助。

3 个答案:

答案 0 :(得分:0)

从头开始处理当前的问题是典型的教义水合问题。

默认情况下,Doctrine会延迟加载关系,这意味着,Doctrine最初会提供不包含任何元素的代理集合,并且仅在以某种方式访问​​实际元素时(例如,使用诸如getProduct( ))。这就是为什么您的“产品”收藏集看起来空白的原因。

您可以通过将关联中的fetch属性设置为EAGER来轻松更改此设置:

// inside Category class
/**
 * @ManyToOne(targetEntity="Product", fetch="EAGER")
 */
 private $products;

但是最终最终将无法使您的代码正常工作,因为当您尝试对具有私有属性的对象进行json_encode时,您只会得到一个空的json。解决您的问题的方法是使用自定义方式来序列化对象。最简单(也可能是最好)的解决方案是使用Symfony序列化器组件。但是您应该知道,仅使用$serializer->serialize($category, 'json');会引发循环引用异常。造成这种情况的原因是(据我猜测)您还在Product类中保留了对Category的引用,如下所示:

// inside Product class
/**
 * @OneToMany(targetEntity="Category")
 */
private $category;

您可以想象,Symfony将尝试序列化一个类别,该类别包含很多产品,这些产品具有一个类别,很多产品...这是一个循环引用。

要绕过此问题,您应该使用如下序列化组:

// inside your controller, supposing you are using autowiring to inject services:

use Symfony\Component\Serializer\SerializerInterface;

public function getTariffsAction(Request $request, SerializerInterface $serializer)
{
    $category = $this->get('doctrine.orm.entity_manager')
             ->getRepository('AppBundle:Category')
             ->findAll();

    $categoryJson = $serializer->serialize($category, 'json', ['groups' => ['tariffs'] ]);

    return $this->json($categoryJson);
}

然后显式配置对象的属性,您希望这样进入实体:

// Category.php
use Symfony\Component\Serializer\Annotation\Groups;
...
/**
 * @ORM\Id
 * @Groups({"tariffs"})
 */
protected $id;

/**
 * @ORM\Column(type="string")
 * @Groups({"tariffs"})
 */
protected $name;

/**
 * @ORM\ManyToOne(targetEntity="Product")
 * @Groups({"tariffs"})
 */
private $product;

// any other attribute you want to include

最后在您的Product.php中:

Product.php

/**
 * @ORM\Id
 * @Groups({"tariffs"})
 */
protected $id;

/**
 * @ORM\Column(type="string")
 * @Groups({"tariffs"})
 */
protected $productName;

// do not include the reference to the category to avoid circular reference
/**
 * @OneToMany(targetEntity="Category")
 */
private $category;

您可以在documentation中找到有关序列化程序组件和序列化组的更多信息。

答案 1 :(得分:0)

在我的Controller更新下方,使用您给我的方法。

public function getTariffsAction(Request $request, SerializerInterface $serializer) 
{
    $category = new Category();
    $category = $this->get('doctrine.orm.entity_manager')
            ->getRepository('AppBundle:Category')
            ->findAll();
    $categoryJson = $serializer->serialize($category , 'json', ['groups' => ['tariffs'] ]);
    return $this->json($categoryJson);
}

当我转储$ category时,我得到了一些我无法粘贴的东西,因为它太多了。使用Postman会使我的计算机出现很多错误(屏幕之一关闭),之后我必须重新启动

答案 2 :(得分:0)

问题已经解决,您绝对正确,这是循环引用,我按照您所说的与小组一起解决了。 (我使用FOSRestBundle进行分组比使用本机symfony方法更容易)