在 symfony JMS PHP 中将单个字符串属性反序列化为对象

Posted

技术标签:

【中文标题】在 symfony JMS PHP 中将单个字符串属性反序列化为对象【英文标题】:Deserialize single string property into object in symfony JMS PHP 【发布时间】:2021-10-14 19:51:46 【问题描述】:

拥有 php、Symfony 4.4、JMS 序列化程序和 json 有效负载(请求正文):


  "quantity": 1,
  "product": 
    "sku": "bla"
  ,
  "myId": 
      "id": "0010N00005GcOhhQAF"
  

此有效负载被发送到我的端点,并且所有内容都正确反序列化为正确的结果 CustomRequest 对象 - 也正确创建了 ProductMyId 等嵌套对象。对于Product 对象来说没问题,因为Product 具有具有多个属性的复杂结构。

但我想要实现的是让myId 的输入更容易。我想拥有它而不是:

  "myId": 
      "id": "0010N00005GcOhhQAF"
  

这很简单:

  "myId": "0010N00005GcOhhQAF"

您可能会问为什么我有简单 id 的课程。它不是简单的 id,它内部有一些特殊的验证和业务逻辑,并且在所有应用程序中都使用,所以为了验证目的,最好有一个对象。

可以说,我希望我的反序列化器自动将那个简单的 id 字符串带入 MyId 类的构造函数中,并返回该对象。 MyId 类是简单的类,例如:

class MyId

   /**
    * @AppAssert\MyId()
    */
    private ?string $value = null;

    public function __construct(string $value)
    
        $this->value = $value;
    

    public function __toString()
    
        return $this->value;
    

仅供参考:我在生成的 CustomRequest 对象中尝试了此注释,但它不起作用

/**
 * @Serializer\Type("App\Model\MyId")
 */
private ?MyId $myId = null;

编辑:另一个重要部分:这是端点如何自动将请求正文转换为CustomRequest 对象。在这里你可以看到,我使用的是ParamConverter

    /**
     * @Rest\Post("/product")
     * @ParamConverter("customRequest", options=
     *     "validator"="groups"="Default","product"="create",
     * )
     */
    public function postCreateProductAction(CustomRequest $customRequest) 
        // ...
    

问题是:如何使用 JMS Serializer 和 Symfony 来使其工作。获取简单的一个字符串以原子方式将其传递给构造函数并从中生成和对象。这甚至可能吗?谢谢

【问题讨论】:

【参考方案1】:

您需要编写自定义 (De)Normalizer。

这是什么:https://symfony.com/doc/current/components/serializer.html#normalizers

如何自定义:https://symfony.com/doc/current/serializer/custom_normalizer.html

【讨论】:

是的,我相信这是一种手动操作的好方法,但我编辑了问题并指定,我需要使用@ParamConverter 的自动方法来完成这项工作。请参阅问题中的编辑,我还添加了一些代码。谢谢【参考方案2】:

我通过使用JMS\Serializer\Handler\SubscribingHandlerInterface 使其工作。使用这种方法,您只需添加在序列化/反序列化过程中启动的回调。请参阅下面的代码,该代码显示了 MyId 对象的确切解决方案。

在此处了解有关此技术的更多信息:https://jmsyst.com/libs/serializer/master/handlers

namespace App\Handlers;

use App\Model\MyId;
use JMS\Serializer\Context;
use JMS\Serializer\GraphNavigatorInterface;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\JsonDeserializationVisitor;
use JMS\Serializer\JsonSerializationVisitor;

class MyIdHandler implements SubscribingHandlerInterface

    /**
     * @return array<int, array<string, int|string>>
     */
    public static function getSubscribingMethods(): array
    
        return [
            [
                'direction' => GraphNavigatorInterface::DIRECTION_SERIALIZATION,
                'format' => 'json',
                'type' => MyId::class,
                'method' => 'serializeMyIdToJson',
            ],
            [
                'direction' => GraphNavigatorInterface::DIRECTION_DESERIALIZATION,
                'format' => 'json',
                'type' => MyId::class,
                'method' => 'deserializeMyIdFromJson',
            ],
        ];
    

    /**
     * @param array<mixed> $type
     */
    public function serializeMyIdToJson(JsonSerializationVisitor $visitor, ?MyId $myId, array $type, Context $context): string
    
        if ($myId === null) 
            return '';
        

        return (string)$myId;
    

    /**
     * @param array<mixed> $type
     */
    public function deserializeMyIdFromJson(JsonDeserializationVisitor $visitor, string $myId, array $type, Context $context): ?MyId
    
        if (empty($myId)) 
            return null;
        

        return new MyId($myId);
    

【讨论】:

以上是关于在 symfony JMS PHP 中将单个字符串属性反序列化为对象的主要内容,如果未能解决你的问题,请参考以下文章

如何在symfony项目中将php版本从7.0降级到5.6?

如何在Symfony2中将json渲染成树枝

Symfony 4/JMS/FOSUser:无法从 FOS\UserBundle 序列化数据

在 Symfony 4.4 流程组件中将参数作为数组传递

在 Symfony2 中将多维数组转换为点表示法

将重音字符 é 插入 Symfony2 中的表单时,如何在 mysql 数据库中将重音字符 é 保存为 é?