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

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

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

问题

# Json Response
{
  "data": {
    "totalCount": 3,
    "version": "v1"
  }
}
<?php
# The object to deserialize into
namespace App;

use JMS\Serializer\Annotation as Serializer;

class ExampleResponse
{
    /**
     * @var int
     *
     * @Serializer\Type("integer")
     * @Serializer\SerializedName("totalCount")
     */
    protected $totalCount;

    /**
     * @var string
     *
     * @Serializer\Type("string")
     * @Serializer\SerializedName("version")
     */
    protected $version;
}
# Deserialization call
# I have to decode the json into an array and then json encode the internals of "data"
$this->serializer->deserialize(
    json_encode(
        json_decode(
            $json,
            true,
            512,
            JSON_THROW_ON_ERROR
        )['data'],
        JSON_THROW_ON_ERROR
    ),
    App\ExampleResponse::class,
    'json'
)
英文:

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

{
  &quot;data&quot;: {
    #result here
  }
}

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:

# Json Response
{
  &quot;data&quot;: {
    &quot;totalCount&quot;: 3,
    &quot;version&quot;: &quot;v1&quot;
  }
}
&lt;?php
# The object to deserialize into
namespace App;

use JMS\Serializer\Annotation as Serializer;

class ExampleResponse
{
    /**
     * @var int
     *
     * @Serializer\Type(&quot;integer&quot;)
     * @Serializer\SerializedName(&quot;totalCount&quot;)
     */
    protected $totalCount;

    /**
     * @var string
     *
     * @Serializer\Type(&quot;string&quot;)
     * @Serializer\SerializedName(&quot;version&quot;)
     */
    protected $version;
}
# Deserialization call
# I have to decode the json into an array and then json encode the internals of &quot;data&quot;
$this-&gt;serializer-&gt;deserialize(
    json_encode(
        json_decode(
            $json,
            true,
            512,
            JSON_THROW_ON_ERROR
        )[&#39;data&#39;],
        JSON_THROW_ON_ERROR
    ),
    App\ExampleResponse::class,
    &#39;json&#39;
)

Is there a better solution?

答案1

得分: 0

可以,但有点繁琐。

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

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

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

class JsonDeserializationSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [[
            'event' => 'serializer.pre_deserialize',
            'method' => 'onPreDeSerialize',
            'format' => 'json', // optional format
            'priority' => 0, // optional priority
        ]];
    }

    public function onPreDeSerialize(PreDeserializeEvent $event): void
    {
        $data = $event->getData();

        if (is_array($data) && array_key_exists('data', $data)) {
            $event->setData($data['data']);
        }
    }
}

还需要配置监听器:

 $serializer = SerializerBuilder::create()->configureListeners(
   fn (EventDispatcher $e) => $e->addSubscriber(new JsonDeserializationSubscriber())
)->build();
$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:

$response = json_decode($json, true);
$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:

class JsonDeserializationSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [[
            &#39;event&#39; =&gt; &#39;serializer.pre_deserialize&#39;,
            &#39;method&#39; =&gt; &#39;onPreDeSerialize&#39;,
            &#39;format&#39; =&gt; &#39;json&#39;, // optional format
            &#39;priority&#39; =&gt; 0, // optional priority
        ]];
    }


    public function onPreDeSerialize(PreDeserializeEvent $event): void
    {
        $data = $event-&gt;getData();

        if (is_array($data) &amp;&amp; array_key_exists(&#39;data&#39;, $data)) {
            $event-&gt;setData($data[&#39;data&#39;]);
        }

    }

And you also need to configure the listener:

 $serializer = SerializerBuilder::create()-&gt;configureListeners(
   fn (EventDispatcher $e) =&gt; $e-&gt;addSubscriber(new JsonDeserializationSubscriber())
)-&gt;build();
$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:

确定