返回

Symfony 序列化期间如何动态添加 DTO 属性?

php

## Symfony 序列化期间动态添加 DTO 属性

引言

在使用 Symfony 序列化器对数据传输对象 (DTO) 进行序列化时,有时我们需要根据外部条件动态添加属性。传统的解决方案涉及创建自定义类,这可能会导致维护问题。本文将探讨一种更通用的方法,无需创建自定义类即可动态添加属性。

问题

我们的目标是根据查询参数 $portal 的值,向对象添加属性 portal。传统的解决方案需要为每个可能的 portal 值创建自定义类,如下所示:

class FooBar {
  # 各种属性
}

class FooBarContainsCustomPropA extends FooBar {
  public string $portal = 'Portal A';
}

class FooBarContainsCustomPropB extends FooBar {
  public string $portal = 'Portal B';
}

随着可能数百个用户定义的入口,这种解决方案变得难以维护。

解决方案

为了避免创建自定义类,我们可以使用 PropertyAccessor 从对象中获取属性。如果属性不存在,我们可以创建该属性并设置其值:

use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessor;

$propertyAccessor = PropertyAccess::createPropertyAccessor();

if (!$propertyAccessor->isPropertyInitialized($my_object, 'portal')) {
  $propertyAccessor->setValue($my_object, 'portal', $portal);
}

步骤:

  1. 使用 PropertyAccess 创建一个 PropertyAccessor 对象。
  2. 检查属性 portal 是否已初始化。
  3. 如果属性未初始化,则创建该属性并设置其值。

示例

让我们看一个示例,展示如何使用此方法根据 $portal 值动态添加 portal 属性:

$content = $response->getContent();
$my_object = $this->serializer->deserialize(
  $response->getContent(),
  FooBar::class."[]",
  'json',
  [ UnwrappingDenormalizer::UNWRAP_PATH => '[data][someObjectList]' ]
);

$propertyAccessor = PropertyAccess::createPropertyAccessor();

if (!$propertyAccessor->isPropertyInitialized($my_object, 'portal')) {
  $propertyAccessor->setValue($my_object, 'portal', $portal);
}

输出

{
  "some": "prop",
  "another": "property",
  "portal": "Portal B"
}

结论

本文介绍了一种使用 PropertyAccessor 在 Symfony 序列化期间动态添加 DTO 属性的方法,无需创建自定义类。这种方法更加通用且易于维护,因为它允许我们根据任何外部条件添加属性。

常见问题解答

  1. PropertyAccessor 可以用于哪些类型的对象?
    PropertyAccessor 可以用于任何实现了 ArrayAccessPropertyAccessInterface 接口的对象。

  2. 为什么使用 isPropertyInitialized 方法?
    isPropertyInitialized 方法检查属性是否已设置或读取,从而避免了不必要的属性创建。

  3. 除了 portal 属性,还可以使用此方法添加其他属性吗?
    是的,此方法可以用于添加任何所需的属性。

  4. 此方法是否适用于嵌套对象?
    是的,PropertyAccessor 可以处理嵌套对象,允许您访问和设置嵌套属性。

  5. 如果属性已存在,此方法会发生什么?
    如果属性已存在,此方法将覆盖其值。