Symfony 5 具有多对多关系的对象序列化超时

问题描述 投票:0回答:2

在我的 Symfony 5 应用程序中,我有一个实体类

Product
,它有两个属性
$categories
$bundles
。产品类与这两个属性都具有多对多关系。当我注释掉其中一个属性时,产品序列化可以完美地工作。但如果这两个属性都存在,序列化就会超时。

产品类的代码摘录。

class Product
{
    /**
     * @ORM\ManyToMany(targetEntity=ProductBundle::class, mappedBy="products")
     */
    private $productBundles;

    /**
     * @ORM\ManyToMany(targetEntity=Category::class, mappedBy="products")
     * @MaxDepth(1)
     */
    private $categories;

}

序列化的代码如下。

    $products = $productRepository->findBySearchQuery($name);
    $productsJson = $serializerInterface->serialize($products, 'json', [
        ObjectNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object) {
            return $object->getId();
        }
    ]);

我也尝试过使用其他一些 Stackoverflow 答案和 @MaxDepth 上建议的 @ORM/JoinTable 注释,但没有运气。如果任何属性被注释掉,该代码将起作用。如果您对此有任何建议,我将不胜感激。

php symfony serialization orm
2个回答
1
投票

好吧,20个产品其实并不算多。所以我猜如果你让关系不受阻碍地序列化,你就会一遍又一遍地输出相同的对象。

我实际上不知道如何使用序列化器可靠地实现这一点。但标准方法可能就足够了。我喜欢通过实体上的

JsonSerializable
接口进行序列化(为简洁起见,省略 ORM 内容):

class Product implements \JsonSerializable {
    public $name;
    public $categories; // relation

    // getters + setters omitted

    // this implements \JsonSerializable
    public function jsonSerialize() {
        return [
            'name' => $this->name,
            'categories' => array_map(function($category) {
                 return $category->jsonSerializeChild();
            }, $this->categories),
        ];
    }

    // this function effectively stops recursion by leaving out relations
    public function jsonSerializeChild() {
        return [
            'name' => $this->name,
        ];
    }
}

如果您在所有实体上实现此功能,您可以非常有效地将序列化深度限制为两个(即“基本”实体及其连接的实体)。

此外,如果您的序列化为 to JSON,则 symfony 序列化器将使用 JsonSerialized 接口(如果已定义)。显然,这不像一些花哨的基于注释的序列化或“智能”序列化器那么优雅,它们实际上设法停止......但它可能会工作得更好......


1
投票

@Jakumi 指出,序列化器在对象属性

$categories
$bundles
上循环。我通过使用序列化组避免了这种情况。

产品类别

class Product
{
    /**
     * @ORM\ManyToMany(targetEntity=ProductBundle::class, mappedBy="products")
     * @Groups("product_listing:read")
     */
    private $productBundles;

    /**
     * @ORM\ManyToMany(targetEntity=Category::class, mappedBy="products")
     * @Groups("product_listing:read")
     */
    private $categories;

}

类别类

class Category
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @Groups("product_listing:read")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     * @Groups("product_listing:read")
     */
    private $name;
}

对序列化器的调用

$products = $productRepository->findBySearchQuery($name);
$productsJson = $serializerInterface->serialize($products, 'json', ['groups' => 'product_listing:read']);

我希望这对将来的人有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.