Общедоступные и частные носители SonataMediaBundle, загруженные в разные папки (веб- и частные)


Я использую SonataMediaBundle и до сих пор публично загружал файлы в папку web Symfony. Вот часть моего файла конфигурации:

contexts:
    default:  # the default context is mandatory
        providers:
            - sonata.media.provider.dailymotion
            - sonata.media.provider.youtube
            - sonata.media.provider.image
            - sonata.media.provider.file
            - sonata.media.provider.vimeo

        formats:
            small: { width: 100 , quality: 70}
            big:   { width: 500 , quality: 70}
    profile_pics:  # the default context is mandatory
        providers: 
            - sonata.media.provider.dailymotion
            - sonata.media.provider.youtube
            - sonata.media.provider.image
            - sonata.media.provider.file
            - sonata.media.provider.vimeo

        formats:
            small: { width: 100 , quality: 70}
            big:   { width: 500 , quality: 70}

cdn:
    server:
        path: %cdn_server_path% # http://media.sonata-project.org/

filesystem:
    local:
        directory:  %kernel.root_dir%/../web/uploads/media
        create:     false

И в моем parameters.yml у меня есть cdn_server_path: /uploads/media/.

Это приведет к загрузке файлов в web/uploads/media/contextname/0001/01/***.

Находясь в общей папке, эти файлы видны всем. Я знаю, что могу изменить эту папку где-нибудь в app/Resources/, но это сделает ВСЕ мои файлы закрытыми, чего я не хочу. Под частным я подразумеваю, что их следует обслуживать каким-то образом с помощью контроллера.

Как я могу разделить некоторые файлы, которые являются общедоступными, и другие, которые являются частными? Есть ли способ заставить определенный контекст загружать файлы иначе, чем другой? Или любым другим способом?

Кроме того, при загрузке файлов в папку приложения/ресурсов их невозможно просмотреть, так как их URL-адрес становится http://website.com/app/Resources/media/profile_pics/0001/01/85e05ab9685b1745af4e64ff98ef91eed6e4ccdf.jpeg{[19] } который не является общедоступным, потому что его нет в веб-папке, только общедоступные файлы, которые есть у Symfony. Как это можно сделать?

РЕДАКТИРОВАТЬ: Мне удалось выполнить часть загрузки (проверьте ответ ниже), но часть извлечения немного хлопотна. Я все еще ищу способ сделать это.

Author: George Irimiciuc, 2015-11-17

2 answers

Хорошо, я почти на месте. Мои файлы загружаются в любую папку, которую я хочу, но у меня проблема с их отображением.

Идея состоит в том, чтобы создать пользовательского провайдера, который имеет свою собственную файловую систему и службы адаптеров. Проблема заключалась в том, что мне нужно было передать службе адаптера папку, в которую я хочу загрузить файлы. Этот адаптер передается в файловую систему, которая затем передается поставщику. Проблема с SonataMediaBundle в том, что он не позволяет вы изменяете каталог адаптера, поэтому вам нужно создать свой собственный и передать его полностью своему поставщику.

Услуги:

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]

Параметры.yml

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

Пользовательский адаптер

use Sonata\MediaBundle\Filesystem\Local;

class PrivateFileAdapter extends Local
{

}

Файловая система

use Gaufrette\Filesystem;

class PrivateFilesystem extends Filesystem
{

}

И, наконец, поставщик

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);

    }
}

Затем добавьте этого поставщика в любой из ваших контекстов sonata_media. Я добавил его в контекст по умолчанию, например:

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

Для создания нового носителя в частном папка:

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

$файл - это содержимое файла, полученное из вашей формы. Это создаст папку app\Resources\media\default\0001\01, в которую будут загружены файлы.

Теперь проблема заключается в их извлечении, так как они не имеют общедоступной ссылки и должны быть извлечены в контроллере. Я создал метод getPrivateMedia() в поставщике, но он работает не так, как предполагалось.

РЕДАКТИРОВАТЬ: Заметил, что сервисы также могут быть определены следующим образом:

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]

Нет необходимости создайте пользовательскую файловую систему или адаптер для поставщика, просто создайте новые службы и передайте каталог адаптеру, затем передайте адаптер файловой системе, а файловую систему пользовательскому поставщику. Это если вам не нужна никакая пользовательская функциональность.

 1
Author: George Irimiciuc, 2015-11-19 11:30:34

У меня была точно такая же проблема, так что большое спасибо за решение для загрузки.

Для загрузки файлов из защищенного каталога - sonata предоставляет метод для этого, поэтому вам даже не нужен пользовательский поставщик, как описано здесь: https://sonata-project.org/bundles/media/master/doc/reference/security.html

Моя реализация этого выглядит так:

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

Контекст с явно определенной политикой безопасности для контроля того, кто получает доступ файлы. Супер администратор в этом случае:

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

В twig вы можете затем получить ссылки на загружаемый ресурс следующим образом:

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

sonata_media_download карты MediaController::downloadAction(), которые реализуют функциональность, которую вы пытались достичь с помощью getPrivateMedia().

Бит, на котором я сейчас застрял, заключается в том, чтобы установить такие вещи, как allowed_extensions и т. Д. Для нового поставщика, поскольку раздел providers не будет принимать private в качестве имени, поэтому я предполагаю, что это должно быть где-то конкретно определено.

РЕДАКТИРОВАТЬ: allowed_extensions и т.д. могут быть переданы как дальнейшие аргументы с помощью определения пользовательской службы поставщика.

 0
Author: Bananaapple, 2018-04-16 10:53:17