Symfony – 如何使用JMS\Serializer指定根来将json数组反序列化为对象

huangapple go评论91阅读模式
英文:

Symfony - How to specify root to deserialize json array to object using JMS\Serializer

问题

  1. # Json Response
  2. {
  3. "data": {
  4. "totalCount": 3,
  5. "version": "v1"
  6. }
  7. }
  1. <?php
  2. # The object to deserialize into
  3. namespace App;
  4. use JMS\Serializer\Annotation as Serializer;
  5. class ExampleResponse
  6. {
  7. /**
  8. * @var int
  9. *
  10. * @Serializer\Type("integer")
  11. * @Serializer\SerializedName("totalCount")
  12. */
  13. protected $totalCount;
  14. /**
  15. * @var string
  16. *
  17. * @Serializer\Type("string")
  18. * @Serializer\SerializedName("version")
  19. */
  20. protected $version;
  21. }
  1. # Deserialization call
  2. # I have to decode the json into an array and then json encode the internals of "data"
  3. $this->serializer->deserialize(
  4. json_encode(
  5. json_decode(
  6. $json,
  7. true,
  8. 512,
  9. JSON_THROW_ON_ERROR
  10. )['data'],
  11. JSON_THROW_ON_ERROR
  12. ),
  13. App\ExampleResponse::class,
  14. 'json'
  15. )
英文:

I receive json responses from a certain server to API requests in this format:

  1. {
  2. &quot;data&quot;: {
  3. #result here
  4. }
  5. }

But I need to do deserialization of the result itself inside "data". I could not find in the documentation how to specify the json deserialization root

Example:

  1. # Json Response
  2. {
  3. &quot;data&quot;: {
  4. &quot;totalCount&quot;: 3,
  5. &quot;version&quot;: &quot;v1&quot;
  6. }
  7. }
  1. &lt;?php
  2. # The object to deserialize into
  3. namespace App;
  4. use JMS\Serializer\Annotation as Serializer;
  5. class ExampleResponse
  6. {
  7. /**
  8. * @var int
  9. *
  10. * @Serializer\Type(&quot;integer&quot;)
  11. * @Serializer\SerializedName(&quot;totalCount&quot;)
  12. */
  13. protected $totalCount;
  14. /**
  15. * @var string
  16. *
  17. * @Serializer\Type(&quot;string&quot;)
  18. * @Serializer\SerializedName(&quot;version&quot;)
  19. */
  20. protected $version;
  21. }
  1. # Deserialization call
  2. # I have to decode the json into an array and then json encode the internals of &quot;data&quot;
  3. $this-&gt;serializer-&gt;deserialize(
  4. json_encode(
  5. json_decode(
  6. $json,
  7. true,
  8. 512,
  9. JSON_THROW_ON_ERROR
  10. )[&#39;data&#39;],
  11. JSON_THROW_ON_ERROR
  12. ),
  13. App\ExampleResponse::class,
  14. &#39;json&#39;
  15. )

Is there a better solution?

答案1

得分: 0

可以,但有点繁琐。

最简单的方法是使用 json_decode 并使用 fromArray 方法反序列化对象:

  1. $response = json_decode($json, true);
  2. $this->serializer->fromArray($response['data'], App\ExampleResponse::class)

另一种解决方案是使用订阅者监听 pre_deserialize 事件:

  1. class JsonDeserializationSubscriber implements EventSubscriberInterface
  2. {
  3. public static function getSubscribedEvents(): array
  4. {
  5. return [[
  6. 'event' => 'serializer.pre_deserialize',
  7. 'method' => 'onPreDeSerialize',
  8. 'format' => 'json', // optional format
  9. 'priority' => 0, // optional priority
  10. ]];
  11. }
  12. public function onPreDeSerialize(PreDeserializeEvent $event): void
  13. {
  14. $data = $event->getData();
  15. if (is_array($data) && array_key_exists('data', $data)) {
  16. $event->setData($data['data']);
  17. }
  18. }
  19. }

还需要配置监听器:

  1. $serializer = SerializerBuilder::create()->configureListeners(
  2. fn (EventDispatcher $e) => $e->addSubscriber(new JsonDeserializationSubscriber())
  3. )->build();
  4. $serializer->deserialize($json, App\ExampleResponse::class, 'json');
英文:

It is possible but a little bit cumbersome.

The easiest approach is to use json_decode and deserialize the object with the fromArray method:

  1. $response = json_decode($json, true);
  2. $this-&gt;serializer-&gt;fromArray($response[&#39;data&#39;], App\ExampleResponse::class)

The other solution is to use a subscriber to listen on the pre_deserialize event:

  1. class JsonDeserializationSubscriber implements EventSubscriberInterface
  2. {
  3. public static function getSubscribedEvents(): array
  4. {
  5. return [[
  6. &#39;event&#39; =&gt; &#39;serializer.pre_deserialize&#39;,
  7. &#39;method&#39; =&gt; &#39;onPreDeSerialize&#39;,
  8. &#39;format&#39; =&gt; &#39;json&#39;, // optional format
  9. &#39;priority&#39; =&gt; 0, // optional priority
  10. ]];
  11. }
  12. public function onPreDeSerialize(PreDeserializeEvent $event): void
  13. {
  14. $data = $event-&gt;getData();
  15. if (is_array($data) &amp;&amp; array_key_exists(&#39;data&#39;, $data)) {
  16. $event-&gt;setData($data[&#39;data&#39;]);
  17. }
  18. }

And you also need to configure the listener:

  1. $serializer = SerializerBuilder::create()-&gt;configureListeners(
  2. fn (EventDispatcher $e) =&gt; $e-&gt;addSubscriber(new JsonDeserializationSubscriber())
  3. )-&gt;build();
  4. $serializer-&gt;deserialize($json, App\ExampleResponse::class, &#39;json&#39;);

huangapple
  • 本文由 发表于 2023年3月1日 15:54:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75600872.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定