如何基于type字段为spatie/data-transfer-object配置不同嵌套DTO类型
解决spatie/data-transfer-object v2中根据字段值动态匹配DTO类型的问题
你当前的问题核心是:spatie/data-transfer-object v2的FlexibleDataTransferObject本身不支持基于字段值自动切换DTO类型,直接用Parameters类映射时会丢失未定义的value/values字段。要实现根据parameters.*.type匹配不同DTO类,必须手动编写遍历处理逻辑,具体方案如下:
1. 定义对应类型的参数DTO类
为每种type创建专属DTO类,确保对应字段被正确声明:
// Formio/Dto/ParametersText.php namespace Formio\Dto; use Spatie\DataTransferObject\FlexibleDataTransferObject; class ParametersText extends FlexibleDataTransferObject { public string $name; public string $type; public string $value; }
// Formio/Dto/ParametersSelect.php namespace Formio\Dto; use Spatie\DataTransferObject\FlexibleDataTransferObject; class ParametersSelect extends FlexibleDataTransferObject { public string $name; public string $type; public array $values; }
保留基础Parameters类作为兜底,处理未匹配到的类型:
// Formio/Dto/Parameters.php namespace Formio\Dto; use Spatie\DataTransferObject\FlexibleDataTransferObject; class Parameters extends FlexibleDataTransferObject { public string $name; public string $type; }
2. 修改Content类,添加动态映射逻辑
在Content的构造函数中,手动遍历parameters数组,根据每个项的type字段实例化对应的DTO类:
// Formio/Dto/Content.php namespace Formio\Dto; use Spatie\DataTransferObject\FlexibleDataTransferObject; class Content extends FlexibleDataTransferObject { /** @var ParametersText[]|ParametersSelect[]|Parameters[] $parameters */ public array $parameters; public function __construct(array $data) { // 处理parameters的动态类型映射 if (isset($data['parameters'])) { // 维护type到DTO类的映射表,便于后续扩展 $typeToDto = [ 'text' => ParametersText::class, 'select' => ParametersSelect::class, ]; $data['parameters'] = array_map(function (array $param) use ($typeToDto) { $dtoClass = $typeToDto[$param['type']] ?? Parameters::class; return new $dtoClass($param); }, $data['parameters']); } parent::__construct($data); } }
3. 验证效果
现在实例化Content时,每个parameter会自动匹配到对应的DTO类,value或values字段也会被正确映射:
$object = [ 'parameters' => [ [ 'name' => 'foo', 'type' => 'text', 'value' => 'bar' ], [ 'name' => 'baz', 'type' => 'select', 'values' => ['foo', 'bar'] ] ] ]; $dto = new \Formio\Dto\Content($object); // 访问对应字段 echo $dto->parameters[0]->value; // 输出 'bar' print_r($dto->parameters[1]->values); // 输出 ['foo', 'bar']
这种方案逻辑清晰、易于扩展,后续新增type只需添加对应的DTO类并更新映射表即可。
内容的提问来源于stack exchange,提问作者marcus
相关产品推荐
相关产品推荐

