具有多对多关系超时的 Symfony 5 对象序列化
Symfony 5 Object Serialization with ManyToMany Relation Times Out
在我的 Symfony 5 应用程序中,我有一个实体 class Product
,它有两个属性 $categories
和 $bundles
。产品 class 与这两个属性都存在多对多关系。当我注释掉其中一个属性时,产品序列化工作完美。但是如果两个属性都存在,序列化超时。
代码摘自产品 class。
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();
}
]);
我曾尝试使用在其他一些 Whosebug 答案和@MaxDepth 中建议的 @ORM/JoinTable 注释,但没有成功。如果任何属性被注释掉,代码就可以工作。如有任何建议,我们将不胜感激。
好吧,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,
];
}
}
如果您在所有实体上实施此操作,您可以非常有效地将序列化深度限制为两个(即“基础”实体及其连接的实体)。
此外,symfony 序列化程序将使用 JsonSerializable 接口,如果它被定义,如果您序列化 到 JSON。显然,这不像一些奇特的 annotation-based 序列化或“智能”序列化程序那样优雅,它们实际上设法停止了……但它可能会更好地工作……
@Jakumi 指出,序列化程序遍历对象属性 $categories
和 $bundles
。我通过使用序列化组避免了这种情况。
产品class
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
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']);
我希望这对以后的人有所帮助。
在我的 Symfony 5 应用程序中,我有一个实体 class Product
,它有两个属性 $categories
和 $bundles
。产品 class 与这两个属性都存在多对多关系。当我注释掉其中一个属性时,产品序列化工作完美。但是如果两个属性都存在,序列化超时。
代码摘自产品 class。
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();
}
]);
我曾尝试使用在其他一些 Whosebug 答案和@MaxDepth 中建议的 @ORM/JoinTable 注释,但没有成功。如果任何属性被注释掉,代码就可以工作。如有任何建议,我们将不胜感激。
好吧,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,
];
}
}
如果您在所有实体上实施此操作,您可以非常有效地将序列化深度限制为两个(即“基础”实体及其连接的实体)。
此外,symfony 序列化程序将使用 JsonSerializable 接口,如果它被定义,如果您序列化 到 JSON。显然,这不像一些奇特的 annotation-based 序列化或“智能”序列化程序那样优雅,它们实际上设法停止了……但它可能会更好地工作……
@Jakumi 指出,序列化程序遍历对象属性 $categories
和 $bundles
。我通过使用序列化组避免了这种情况。
产品class
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
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']);
我希望这对以后的人有所帮助。