代码之家  ›  专栏  ›  技术社区  ›  eldiablo62

Symfony 6串行器

  •  0
  • eldiablo62  · 技术社区  · 1 年前

    我需要用symfony 6将这些数据反规范化

    array:4 [
      "createdAt" => array:3 [
        "date" => "2024-01-09 17:04:37.209330"
        "timezone_type" => 3
        "timezone" => "Europe/Paris"
      ]
      "utilisateur" => "phpunit"
      "type" => "CREATION"
      "texte" => "creation de la demande"
    ]
    

    到此对象

    class Historique
    {
        public \DateTime $createdAt;
    
        public function __construct(public readonly string $utilisateur, public readonly string $type, public readonly ?string $texte)
        {
            $this->createdAt = new \DateTime();
        }
    
        public function getTypeLabel(): string
        {
            return HistoriqueTypeEnum::getLabelName($this->type);
        }
    }
    

    我已经使用了此代码,但我有一个问题来取消规范化 DateTime 对象

    $normalizers = [
        new DateTimeNormalizer(),
        new ObjectNormalizer(null, null, null, new ReflectionExtractor()),
        new BackedEnumNormalizer(),
    ];
    $serializer = new Serializer($normalizers, [new JsonEncoder()]);
    $serializer->denormalize($historique, Historique::class, 'json', [DateTimeNormalizer::FORMAT_KEY => 'Y-m-d H:i:s',]);
    

    我收到以下错误:

    数据不是字符串、空字符串或null;您应该传递一个可以使用传递的格式进行解析的字符串或一个有效的DateTime字符串。

    如果我像这样更改归一化器的顺序:

    $normalizers = [
        new ObjectNormalizer(null, null, null, new ReflectionExtractor()),
        new BackedEnumNormalizer(),
        new DateTimeNormalizer(),
    ];
    

    我收到以下错误:

    无法从序列化数据创建“DateTimeZone”的实例,因为其构造函数要求存在以下参数:“$timezone”。")

    0 回复  |  直到 1 年前
        1
  •  0
  •   SubCore    1 年前

    DateTimeNormalizer类需要一个有效的DateTime字符串。您可以更改数据数组,将createdAt键设置为日期字符串,并使用设置时区,而不是忽略DateTime对象 DateTimeNormalizer::TIMEZONE_KEY

    $historique = [
      "createdAt" => [
        "date" => "2024-01-09 17:04:37.209330",
        "timezone_type" => 3,
        "timezone" => "Europe/Paris"
      ],
      "utilisateur" => "phpunit",
      "type" => "CREATION",
      "texte" => "creation de la demande",
    ];
    
    $createdAt = $historique['createdAt'];
    $historique['createdAt'] = $createdAt['date'];
    
    $normalizers = [
        new DateTimeNormalizer(),
        new ObjectNormalizer(null, null, null, new ReflectionExtractor()),
        new BackedEnumNormalizer(),
    ];
    $serializer = new Serializer($normalizers, [new JsonEncoder()]);
    $object = $serializer->denormalize(
        $historique, 
        Historique::class, 
        'json', 
        [
            DateTimeNormalizer::TIMEZONE_KEY => $createdAt['timezone'],
        ]
    );
    dump($object);
    
    // Result:
    // ^ Historique^ {#114
    //   +createdAt: DateTime @1704816277 {#104
    //     date: 2024-01-09 17:04:37.209330 Europe/Paris (+01:00)
    //   }
    //   +utilisateur: "phpunit"
    //   +type: "CREATION"
    //   +texte: "creation de la demande"
    // }
    
        2
  •  0
  •   Bademeister    1 年前

    如果您的示例数组是输入,那么您需要一个单独的去规范化器来满足您的需求。

    我的日期时间类型

    要识别属性,请创建自己的类型。此类型继承\DateTime。

    namespace App\Normalizer;
    
    class MyDateTimeType extends \DateTime { }
    

    历史

    class Historique
    {
        public MyDateTimeType $createdAt;
    
        public function __construct(public readonly string $utilisateur, public readonly string $type, public readonly ?string $texte)
        {
            $this->createdAt = new MyDateTimeType();
        }
    
        public function getTypeLabel(): string
        {
            return $this->type;
        }
    }
    

    MyDateTimeTypeDenormalizer

    DateTimeNormalizer是为规范化进程继承的。

    namespace App\Normalizer;
    
    use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
    use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
    use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
    
    class MyDateTimeTypeDenormalizer extends DateTimeNormalizer implements DenormalizerInterface
    {
        public function denormalize(mixed $data, string $type, string $format = null, array $context = []): \DateTimeInterface
        {
            return new MyDateTimeType($data['date'], new \DateTimeZone($data['timezone']));
        }
    
        public function supportsDenormalization(mixed $data, string $type, string $format = null): bool
        {
            return MyDateTimeType::class === $type;
        }
    }
    

    示例+测试

    use App\Normalizer\Historique;
    use App\Normalizer\MyDateTimeTypeDenormalizer;
    use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
    use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
    use Symfony\Component\Serializer\Encoder\JsonEncoder;
    use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
    use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
    use Symfony\Component\Serializer\Normalizer\BackedEnumNormalizer;
    use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
    use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
    use Symfony\Component\Serializer\Serializer;
    
    class HistoriqueTest extends KernelTestCase
    {
        public function testHistorique()
        {
            $historique = [
                "createdAt" => [
                    "date" => "2024-01-09 17:04:37.209330",
                    "timezone_type" => 3,
                    "timezone" => "Europe/Paris"
                ],
                "utilisateur" => "phpunit",
                "type" => "CREATION",
                "texte" => "creation de la demande"
            ];
    
            $normalizers = [
                new MyDateTimeTypeDenormalizer(),
                new ObjectNormalizer(
                    new ClassMetadataFactory(new AnnotationLoader(null)),
                    null,
                    null,
                    new ReflectionExtractor()
                ),
                new BackedEnumNormalizer()
            ];
    
            $serializer = new Serializer($normalizers, [new JsonEncoder()]);
    
            $result = $serializer->denormalize(
               $historique,
               Historique::class,
               'json',
               [DateTimeNormalizer::FORMAT_KEY => 'Y-m-d H:i:s']
            );
    
            $this->assertSame('2024-01-09T17:04:37+01:00', $result->createdAt->format('c'));
        }
    }