Public and private Media of SonataMediaBundle uploaded in different folders (web and private) Public and private Media of SonataMediaBundle uploaded in different folders (web and private) symfony symfony

Public and private Media of SonataMediaBundle uploaded in different folders (web and private)


Alright I'm almost there. My files are being uploaded to any folder I want, but I have the problem of getting them to be displayed.

The idea is to create a custom provider that has its own filesystem and adapter services. The problem was that I needed to pass the adapter service the folder in which I want the files to be uploaded. That adapter is passed to the filesystem which is then passed to the provider. The problem with SonataMediaBundle is that it doesn't let you modify the directory of the adapter, so you have to create your own and pass it all the way up to your provider.

Services:

sonata.media.provider.private:    class: MedAppBundle\Services\PrivateFilesProvider    tags:      - { name: sonata.media.provider }    arguments: [%private_provider_name%,@medapp_private.filesystem,@sonata.media.cdn.server,@sonata.media.generator.default,@sonata.media.thumbnail.format]medapp_private.filesystem:    class: MedAppBundle\Services\PrivateFilesystem    arguments: [@medapp_private.adapter]medapp_private.adapter:    class: MedAppBundle\Services\PrivateFileAdapter    arguments: [%private_filesystem_directory%,true]

parameters.yml

private_filesystem_directory: %kernel.root_dir%/Resources/mediaprivate_provider_name: sonata.media.provider.private

The custom adapter

use Sonata\MediaBundle\Filesystem\Local;class PrivateFileAdapter extends Local{}

The filesystem

use Gaufrette\Filesystem;class PrivateFilesystem extends Filesystem{}

And finally, the provider

use Application\Sonata\MediaBundle\Entity\Media;use Gaufrette\Filesystem;use Sonata\MediaBundle\CDN\CDNInterface;use Sonata\MediaBundle\Generator\GeneratorInterface;use Sonata\MediaBundle\Provider\FileProvider;use Sonata\MediaBundle\Thumbnail\ThumbnailInterface;class PrivateFilesProvider extends FileProvider{    public function getPrivateMedia(Media $media)    {        // $path = $this->generatePublicUrl($media, 'reference');        //  $ppath = $this->generatePrivateUrl($media, "reference");        $content = $this->getReferenceFile($media)->getContent();        header('Content-Type: ' . $media->getContentType());        return 'data:' .  $media->getContentType() . ';base64,' . base64_encode($content);    }}

Then, add this provider to any of your sonata_media contexts. I've added it to the default context, for example:

sonata_media:    db_driver: doctrine_orm     default_context: default     contexts:        default:              providers:                - sonata.media.provider.dailymotion                - sonata.media.provider.youtube                - sonata.media.provider.image                - sonata.media.provider.file                - sonata.media.provider.vimeo                - sonata.media.provider.private

To create a new Media in the private folder:

$media = new Media();        $media->setBinaryContent($file);$media->setContext('default');$media->setProviderName('sonata.media.provider.private');$this->em->persist($media);$this->em->flush();

$file is the file content that came from your form.This will create the folder app\Resources\media\default\0001\01 in which the files will be uploaded.

Now the problem is retrieving them, since they don't have a public link and need to be retrieved in a controller. I've created a getPrivateMedia() method in the provider, but it isn't working as intended.

EDIT:Noticed that the services could also be defined like so:

sonata.media.provider.private:    class: MedAppBundle\Services\PrivateFilesProvider    tags:      - { name: sonata.media.provider }    arguments: [%private_provider_name%,@medapp_private.filesystem,@sonata.media.cdn.server,@sonata.media.generator.default,@sonata.media.thumbnail.format,%kernel.root_dir%]medapp_private.filesystem:    class: Gaufrette\Filesystem    arguments: [@medapp_private.adapter]medapp_private.adapter:    class: Sonata\MediaBundle\Filesystem\Local    arguments: [%private_filesystem_directory%,true]

There is no need to create a custom filesystem or adapter for the provider, just create new services and pass the directory to the adapter, then pass the adapter to the filesystem and the filesystem to the custom provider. This is if you don't need any custom functionality.


I've had the exact same problem so thanks very much for the upload solution.

For downloading the files from the secured directory - sonata provides a method for that so you don't even need the custom provider as outlined here: https://sonata-project.org/bundles/media/master/doc/reference/security.html

My implementation of this looks like so:

services:    sonata.media.provider.private:        class: Sonata\MediaBundle\Provider\FileProvider        tags:            - { name: sonata.media.provider }        arguments:            - 'sonata.media.provider.private'            - '@app.sonata.media.private.filesystem'            - '@sonata.media.cdn.server'            - '@sonata.media.generator.default'            - '@sonata.media.thumbnail.format'    app.sonata.media.private.filesystem:        class: Gaufrette\Filesystem        arguments: ['@app.sonata.media.private.adapter']    app.sonata.media.private.adapter:        class: Sonata\MediaBundle\Filesystem\Local        arguments:             - "%kernel.root_dir%/../doclib/uploads"            - true

Context with an explicitly defined security policy to control who gets to access the files. Super admin in this case:

sonata_media:    contexts:        privatefiles:            download:                strategy: sonata.media.security.superadmin_strategy                mode: http            providers:                - sonata.media.provider.private

In twig you can then get links to the downloadable resource like so:

{{ path('sonata_media_download', { 'id':media|sonata_urlsafeid  }) }}

sonata_media_download maps MediaController::downloadAction(), which implements the functionality you tried to achieve with getPrivateMedia().

The bit I am now stuck on is to set stuff like allowed_extensions etc for the new provider as the providers section won't accept private as name so I assume this needs specifically defined somewhere.

EDIT: allowed_extensions etc can be passed as further arguments via the custom provider service definition.