我正在使用SonataMediaBundle,到目前为止,我一直在Symfony的web
文件夹中公开上传文件。这是我的配置文件的一部分:
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/
中的某个位置更改此文件夹,但这会使我的所有文件都是私有的,这是我不想要的。私下里,我的意思是,他们应该由一个管理员服务,不知何故。
如何将一些文件分离为公共文件和其他文件分离为私人文件?有没有一种方法可以使某个上下文上传的文件与另一个不同?或者其他方式?
此外,当将文件上传到app/Resources文件夹时,由于其url变为http://website.com/app/Resources/media/profile_pics/0001/01/85e05ab9685b1745af4e64ff98ef91eed6e4ccdf.jpeg它不是公共的,因为它不在web文件夹中,这是Symfony拥有的唯一公共文件。如何做到这一点?
EDIT:我已经完成了上传部分(检查下面的答案),但检索部分有点麻烦。我仍在寻找一种方法。
好吧,我快到了。我的文件被上传到我想要的任何文件夹,但我有问题让它们显示出来。
其想法是创建一个具有自己的文件系统和适配器服务的自定义提供程序。问题是我需要将文件上传到的文件夹传递给适配器服务。该适配器被传递给文件系统,然后文件系统被传递给提供者。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();
$file是来自表单的文件内容。这将创建文件将上载到的文件夹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]
不需要为提供程序创建自定义文件系统或适配器,只需创建新服务并将目录传递给适配器,然后将适配器传递给文件系统,将文件系统传递给自定义提供程序即可。这是如果您不需要任何自定义功能。
我也遇到过同样的问题,所以非常感谢上传解决方案。
对于从安全目录下载文件,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
在trick中,您可以获得可下载资源的链接,如下所示:
{{ path('sonata_media_download', { 'id':media|sonata_urlsafeid }) }}
sonata_media_download
映射MediaController::downloadAction()
,它实现了您尝试使用getPrivateMedia()
实现的功能。
我现在坚持的是为新的提供者设置allowed_extensions
等内容,因为providers
部分不接受private
作为名称,所以我认为这需要在某个地方进行专门定义。
EDIT:allowed_extensions
等可以通过自定义提供程序服务定义作为进一步的参数传递。