Rafael Bermúdez
Rafael Bermúdez

Reputation: 143

How to get the image url from a gallery in SonataMediaBundle, for use with FOSRestBundle?

I'm working on a mobile app that has to show some images of houses from a server. I have installed Symfony2, FOSRestBundle and Sonata Media Bundle for the backend.

In order to get the houses images URLs, I have configured FOSRestBundle for an entity named Property which has a gallery field. This is the REST controller

class PropertiesController extends FOSRestController
{

    public function getPropertiesAction()
    {
        $response = $this->getDoctrine()->getRepository('ComissionBundle:Property')->findAll();
        if ($response == null){
            return "No properties";
        }
        else{
            return $response;
        }

    }

}

But i get this:

[  
   {  
      "id":2,
      "name":"test",
      "city":"test",
      "address":"test",
      "sector":"test",
      "area":0,
      "rooms":112343,
      "price":0,
      "gallery":{  
         "context":"default",
         "name":"test",
         "enabled":false,
         "updated_at":"2016-08-26T17:18:51+0200",
         "created_at":"2016-08-26T17:18:51+0200",
         "default_format":"default_small",
         "id":1
      }
   }
]

As you can see, there are no media objects.

Then, I tried with a customized repository method:

class PropertyRepository extends EntityRepository
{
    public function findMainInfoElements($elements)
    {
        $em = $this->getEntityManager();

        $queryText  = "SELECT u, g, h FROM ComissionBundle:Property u JOIN u.gallery g JOIN g.galleryHasMedias h";

        $query = $em->createQuery($queryText);

        return $query->setMaxResults($elements)->getResult();
    }
}

but the result is the same.

How can i get the URLs from the gallery in order to show them in the mobile app? (Especially the thumb images that Sonata Media Bundle generates, which are better for the app performance)

Upvotes: 1

Views: 1480

Answers (2)

campsjos
campsjos

Reputation: 1415

Here's is how I did it in a legacy project that I'm working on, adapting the code suggested by @seltzlab:

<?php

namespace Casinos\ApiBundle\Serializer\Handler;

use Application\Sonata\MediaBundle\Entity\Gallery;

use JMS\Serializer\JsonSerializationVisitor;
use JMS\Serializer\Context;
use Sonata\MediaBundle\Provider\ImageProvider;

class MediaGalleryHandler
{
    /**
     * @var ImageProvider
     */
    private $imageProvider;

    public function __construct(ImageProvider $imageProvider)
    {
        $this->imageProvider = $imageProvider;
    }

    public function serializeMedia(JsonSerializationVisitor $visitor, Gallery $media, array $type, Context $context)
    {
        $serializedMedias = [];
        foreach ($media->getGalleryHasMedias() as $galleryHasMedia) {
            $media = $galleryHasMedia->getMedia();
            $serializedMedias[] = $this->imageProvider->generatePublicUrl($media, "reference");
        }

        if ($visitor->getRoot() === null) {
            $visitor->setRoot($serializedMedias);
        }

        return $serializedMedias;
    }
}

Upvotes: 0

seltzlab
seltzlab

Reputation: 340

I guess you should join the galleryHasMedia entity with the Media entity too in the PropertyRepository query, but it will not be enough. You should create a custom serialization handler for the Media entity too.

Declare the serialization handler

myapp.serialization.media_handler:
    class: Path\ToYourApp\Serializer\MediaSerializationHandler
    tags:
        - { name: jms_serializer.handler, type: Path\ToYourMedia\Entity\Media, direction: serialization, format: json, method: serializeMedia }
    arguments: [ @sonata.media.provider.image, @sonata.media.provider.file ]

Create the serialization handler

<?php

namespace Camelot\Social\ApiBundle\Serializer;

use Path\ToYourMedia\Entity\Media;

use JMS\Serializer\JsonSerializationVisitor;
use JMS\Serializer\Context;
use Sonata\MediaBundle\Provider\ImageProvider;
use Sonata\MediaBundle\Provider\FileProvider;

class MediaSerializationHandler
{
    /**
     * @var ImageProvider
     */
    private $imageProvider;

    /**
     * @var FileProvider
     */
    private $fileProvider;

    public function __construct(ImageProvider $imageProvider, FileProvider $fileProvider)
    {
        $this->imageProvider = $imageProvider;
        $this->fileProvider = $fileProvider;
    }

    public function serializeMedia(JsonSerializationVisitor $visitor, Media $media, array $type, Context $context)
    {

        switch ($media->getProviderName()) {
            case 'sonata.media.provider.file':
                $serialization = $this->serializeFile($media);
                break;

            case 'sonata.media.provider.image':
                $serialization = $this->serializeImage($media);
                break;

            default:
                throw new \RuntimeException("Serialization media provider not recognized");
        }

        if ($visitor->getRoot() === null) {
            $visitor->setRoot($serialization);
        }

        return $serialization;
    }

    private function serializeImage(Media $media)
    {
        // here you can provide one ore more URLs based on your SonataMedia configuration
        // you can also add some more properties coming from the media entity based on your needs (e.g. authorName, description, copyright etc)
        return [
            "url" => [
                "orig" => $this->imageProvider->generatePublicUrl($media, "reference"),
                "small" => $this->imageProvider->generatePublicUrl($media, "default_small"),
                "big" => $this->imageProvider->generatePublicUrl($media, "default_big"),
            ]
        ];
    }

    private function serializeFile(Media $media)
    {
        return [
            "name" => $media->getName(),
            "size" => $media->getSize(),
            "url" => $this->fileProvider->generatePublicUrl($media, 'reference')
        ];
    }
}

Upvotes: 1

Related Questions