Ivan Kalita
Ivan Kalita

Reputation: 2287

JMSSerializerBundle - preserve relation name

I'm using Symfony2 with JMSSerializerBundle. And I'm new with last one =) What should I do in such case:

I have Image model. It contains some fields, but the main one is "name". Also, I have some models, which has reference to Image model. For example User and Application. User model has OneToOne field "avatar", and Application has OneToOne field "icon". Now, I want to serialize User instance and get something like

{
     ...,
     "avatar": "http://example.com/my/image/path/image_name.png",
     ....
}

Also, I want to serialize Application and get

{
    ...,
    "icon": "http://example.com/my/image/path/another_image_name.png",
    ...
}

I'm using @Inline annotation on User::avatar and Application::icon fields to reduce Image object (related to this field) to single scalar value (only image "name" needed). Also, my Image model has ExclusionPolicy("all"), and exposes only "name" field. For now, JMSSerializer output is

(For User instance)
{
    ...,
    "name": "http://example.com/my/image/path/image_name.png",
    ...
}

(For Application instance)
{
    ...,
    "name": "http://example.com/my/image/path/another_image_name.png",
    ...
}

The question is: How can I make JMSSerializer to preserve "avatar" and "icon" keys in serialized array instead of "name"?

Upvotes: 0

Views: 288

Answers (1)

Ivan Kalita
Ivan Kalita

Reputation: 2287

Finally, I found solution. In my opinion, it is not very elegant and beautiful, but it works.

  1. I told to JMSSerializer, that User::avatar and Application::icon are Images. To do that, I used annotation @Type("Image")

    //src\AppBundle\Entity\User.php
    //...        
    /**
     * @var integer
     *
     * @ORM\OneToOne(targetEntity="AppBundle\Entity\Image")
     * @ORM\JoinColumn(name="avatar", referencedColumnName="id")
     *
     * @JMS\Expose()
     * @JMS\Type("Image")
     */
    private $avatar;
    //...
    
    //src\AppBundle\Entity\Application.php
    //...
    /**
     * @var integer
     *
     * @ORM\OneToOne(targetEntity="AppBundle\Entity\Image")
     * @ORM\JoinColumn(name="icon", referencedColumnName="id")
     *
     * @JMS\Expose()
     * @JMS\Type("Image")
     */
    private $icon;
    //...
    
  2. I implemented handler, which serializes object with type Image to json.

    <?php
    //src\AppBundle\Serializer\ImageTypeHandler.php
    namespace AppBundle\Serializer;
    
    
    use AppBundle\Entity\Image;
    use JMS\Serializer\Context;
    use JMS\Serializer\GraphNavigator;
    use JMS\Serializer\Handler\SubscribingHandlerInterface;
    use JMS\Serializer\JsonSerializationVisitor;
    use Symfony\Component\HttpFoundation\Request;
    
    class ImageTypeHandler implements SubscribingHandlerInterface
    {
        private $request;
    
        public function __construct(Request $request) {
            $this->request = $request;
    
        }
    
        static public function getSubscribingMethods()
        {
            return [
                [
                    'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                    'format' => 'json',
                    'type' => 'Image',
                    'method' => 'serializeImageToWebPath'
                ]
            ];
        }
    
        public function serializeImageToWebPath(JsonSerializationVisitor $visitor, Image $image = null, array $type, Context $context)
        {
            $path = $image ? "http://" . $this->request->getHost() . "/uploads/images/" . $image->getPath() : '';
    
            return $path;
        }
    }
    
  3. And the last step is to register this handler. I also injected request service to generate full web path to image in my handler.

    app.image_type_handler:
        class: AppBundle\Serializer\ImageTypeHandler
        arguments: ["@request"]
        scope: request
        tags:
            - { name: jms_serializer.subscribing_handler }
    

Also, you can use this workaround, to modify serialized data in post_serialize event.

Upvotes: 2

Related Questions