2013-12-19 11 views
5

JMSSerializerを使用してシリアル化とデシリアライズで単一のオブジェクトプロパティを処理したいと考えています。私たちは、このクラスを持っているSuposing:私は、タスクのインスタンスを返すしたいJMSSerializer(単一のプロパティを扱う)で入力フィールドと出力フィールドをフォーマットする

class Task { 

    const STATUS_PENDING = 0; 
    const STATUS_OVER = 1; 

    protected $status; 

    /* getter and setter */ 

    public function getStatusLabel() 
    { 
     return ['pending', 'over'][$this->getStatus()]; 
    } 

    public static function getStatusFromLabel($label) 
    { 
     return [ 
      'pending' => self::STATUS_PENDING, 
      'over' => self::STATUS_OVER 
     ][$label]; 
    } 
} 

は(FOSRestBundleを使用して)REST APIを投げました。問題は、$status属性の生の値ではなく、「ラベル」の値を返すことです。

Task: 
    exclusion_policy: ALL 
    properties: 
     status: 
      expose: true 
      type: string 

「保留中」または「オーバー」(getStatusLabelを使用して)私のシリアライズされたオブジェクトでのJMSシリアライザは、0または1である生の値を考慮し、私は送信したい:このような私のシリアル化の設定

。また、逆シリアル化の逆作業を実行します(getStatusFromLabelを使用)。

私はvirtual_propertiesについて教えましたが、それはセリシング方向でのみ機能します。

私はこのように見ているカスタムハンドラを試してみました:

class TaskHandler implements SubscribingHandlerInterface 
{ 
    public static function getSubscribingMethods() 
    { 
     return [ 
      [ 
       'direction' => GraphNavigator::DIRECTION_SERIALIZATION, 
       'format' => 'json', 
       'type' => 'Task', 
       'method' => 'serializeToArray', 
      ] 
     ]; 
    } 

    public function serializeToArray(JsonSerializationVisitor $visitor, Task $task, array $type, Context $context) 
    { 
     $task->setStatus($task->getStatusLabel()); 
     return $visitor->getNavigator()->accept($task, $type, $context); 
    } 

しかし、それは明らかに動作しません!

どのように私のカスタムgetterをserilizationとdeserializationの両方の方向で呼び出すことができますか?

答えて

10

最終的に答えが見つかりました。私はここでやっている何

use JMS\Serializer\EventDispatcher\EventSubscriberInterface; 
use JMS\Serializer\EventDispatcher\Events; 
use JMS\Serializer\EventDispatcher\PreDeserializeEvent; 
use JMS\Serializer\EventDispatcher\PreSerializeEvent; 

class TaskSubscriber implements EventSubscriberInterface 
{ 
    public static function getSubscribedEvents() 
    { 
     return [ 
      [ 
       'event' => Events::PRE_SERIALIZE, 
       'format' => 'json', 
       'class' => 'Task', // fully qualified name here 
       'method' => 'onPreSerializeTaskJson', 
      ], 
      [ 
       'event' => Events::PRE_DESERIALIZE, 
       'format' => 'json', 
       'class' => 'Task', 
       'method' => 'onPreDeserializeTaskJson', 
      ] 
     ]; 
    } 

    public function onPreSerializeTaskJson(PreSerializeEvent $event) 
    { 
     /** @var Task $task */ 
     $task = $event->getObject(); 

     $task->setStatus($task->getStatusLabel()); 
    } 

    public function onPreDeserializeTaskJson(PreDeserializeEvent $event) 
    { 
     $data = $event->getData(); 

     $data['status'] = Task::getStatusFromLabel($data['status']); 

     $event->setData($data); 
    } 
} 

:私はこのようなイベントsubsciberを作成する必要がありました

まず

  • を直列化する前に、私はラベルと私のTaskオブジェクトのステータス値を設定します
  • デシリアライズする前に、ラベルから生の整数値にシリアル化されたオブジェクトの値を変更します

このソリューションでは、シリアライザにフィールドを公開する必要があります(expose: trueまたは@Expose)。

私は、symfonyのサービスとしてサブスクライバをタグjms_serializer.event_subscriberと宣言しました。

serializer.subscriber.task: 
    class: %serializer.subscriber.task.class% # TaskSubscriber class path 
    tags: 
     - { name: jms_serializer.event_subscriber } 

これは機能します。

シリアライズとデシリアライズの両方を行うのに最適な方法です。また、post_serializeイベントとpost_deserializeイベントのデータを操作することもできます。たとえば、シリアル化されたオブジェクトに新しいフィールドを追加します。

use JMS\Serializer\EventDispatcher\ObjectEvent; 

public function onPostSerializeTaskJson(ObjectEvent $event) 
{ 
    /** @var Task $task */ 
    $task = $event->getObject(); 

    $event->getVisitor()->addData('nb_related', count($task->getRelatedTasks())); 
} 
+0

ありがとうございます。 @all 'class'の完全修飾名はバックスラッシュの先頭にない(デバッグするのが難しい)必要があると考えてください。 – ownking

関連する問題