ashleydawson / doctrine-flysystem-bundle
为 Symfony 2 中的 Doctrine 实体添加 flysystem 存储行为(特性)
Requires
- php: >=5.4
- ashleydawson/multibundle: ~1.0
- doctrine/orm: ~2.3|~3.0
- oneup/flysystem-bundle: ~1.0
- symfony/symfony: ~2.3|~3.0
Requires (Dev)
- phpunit/phpunit: 4.2.6
This package is auto-updated.
Last update: 2024-09-20 22:17:58 UTC
README
在 Symfony 2 中为 Doctrine 实体添加 flysystem 存储行为
要求
>= PHP 5.4
>= Symfony Framework 2.3
Doctrine 支持
- Doctrine ORM 支持 - 完整
- Doctrine ODM 支持 - 不完整
简介
我创建了这个包来扩展 Flysystem 文件系统抽象。实际上,这个库扩展了为 Symfony 2 定制的 FlysystemBundle。
此包在 Doctrine 实体上实现了一个“上传文件”处理程序,允许 Flysystem 将文件作为 Doctrine 实体生命周期的一部分进行存储。
该包的主要类是一个 特性,它可以应用于任何 Doctrine 实体,使 Flysystem 存储处理程序能够持久化文件细节与实体一起。
安装
您可以通过 Composer 安装 Doctrine Flysystem Bundle。为此,只需在您的 composer.json 文件中添加该包,如下所示
{ "require": { "ashleydawson/doctrine-flysystem-bundle": "0.8.*" } }
运行 composer update 以安装包。然后您需要在您的 app/AppKernel.php
文件中注册该包。下面的第一个示例使用 MultiBundle 库来注册包及其依赖项。有关更多信息,请参阅 MultiBundle 文档。
// app/AppKernel.php $bundles = array( // ..., ); // Do this after the production bundles are set \AshleyDawson\DoctrineFlysystemBundle\AshleyDawsonDoctrineFlysystemBundle::registerInto($bundles); // ...
或者您可以这样做(传统方式)
// app/AppKernel.php // ... $bundles = array( // ... new Oneup\FlysystemBundle\OneupFlysystemBundle(), // Doctrine Flysystem Bundle depends on this new AshleyDawson\DoctrineFlysystemBundle\AshleyDawsonDoctrineFlysystemBundle(), ); // ...
配置
接下来,您需要配置至少一个文件系统来存储文件。以下是一个示例,但更好的示例可以在 FlysystemBundle 文档 中找到。
# app/config/config.yml oneup_flysystem: adapters: my_adapter: local: directory: %kernel.root_dir%/cache filesystems: my_filesystem: adapter: my_adapter mount: my_filesystem_mount_name
注意:此行 mount: my_filesystem_mount_name
很重要,因为此包使用在此定义的挂载前缀来引用文件系统
用法
为了使用此包,您必须将给定的特性应用于您希望存储上传文件的实体。
<?php namespace Acme\DemoBundle\Entity; use Doctrine\ORM\Mapping as ORM; use AshleyDawson\DoctrineFlysystemBundle\ORM\StorableTrait; /** * Post * * @ORM\Table() * @ORM\Entity */ class Post { /** * Use the storable file trait */ use StorableTrait; /** * @var integer * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string * * @ORM\Column(name="title", type="string", length=255) */ private $title; /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Set title * * @param string $title * @return Post */ public function setTitle($title) { $this->title = $title; return $this; } /** * Get title * * @return string */ public function getTitle() { return $this->title; } /** * Get the Flysystem filesystem mount prefix as * configured in https://github.com/1up-lab/OneupFlysystemBundle/blob/master/Resources/doc/filesystem_create.md#use-the-mount-manager * * <code> * // A single filesystem... * * public function getFilesystemMountPrefix() * { * return 'example_filesystem_mount_prefix'; * } * * // Or a list of filesystems... * * public function getFilesystemMountPrefix() * { * return [ * 'example_filesystem_mount_prefix_01', * 'example_filesystem_mount_prefix_02', * ]; * } * </code> * * @return string|array */ public function getFilesystemMountPrefix() { return 'my_filesystem_mount_name'; // This is the mount prefix configured in app/config/config.yml } }
getFilesystemMountPrefix()
方法定义了 Flysystem 挂载前缀,其中您希望将与此实体关联的文件存储,如 app/config/config.yml
中定义。
注意:如果 getFilesystemMountPrefix()
返回挂载前缀数组,则文件将存储在每个文件系统中
特性将为实体添加四个属性
- fileName : string
- 客户端上传文件的原始名称
- 列名:file_name
- 例如:foobar.gif
- fileStoragePath : string
- 文件的存储路径。默认为文件名(如上所述)
- 列名:file_storage_path
- 例如:/path/to/foobar.gif
- fileMimeType : string
- 客户端上传文件的解析 MIME 类型
- 列名:file_mime_type
- 例如:image/gif
- fileSize : integer
- 以字节为单位的文件大小
- 列名:file_size
- 例如:2324
在使用此实体之前,您需要更新您的模式。
app/console doctrine:schema:update [--dump-sql | --force]
表单类型
使用实体和表单类型的示例
<?php namespace Acme\DemoBundle\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; /** * Class PostType * * @package Acme\DemoBundle\Form */ class PostType extends AbstractType { /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('title', 'text') ->add('uploaded_file', 'file', [ 'required' => false, ]) ; } /** * {@inheritdoc} */ public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver ->setDefaults([ 'data_class' => 'Acme\DemoBundle\Entity\Post', ]) ; } /** * {@inheritdoc} */ public function getName() { return 'post'; } }
注意:名为 "uploaded_file" 的字段映射到 AshleyDawson\DoctrineFlysystemBundle\ORM\StorableTrait
中的参数。如果您想更改此设置,只需为您的实体添加一个访问器作为代理
<?php namespace Acme\DemoBundle\Entity; use Doctrine\ORM\Mapping as ORM; use AshleyDawson\DoctrineFlysystemBundle\ORM\StorableTrait; use Symfony\Component\HttpFoundation\File\UploadedFile; /** * Post * * @ORM\Table() * @ORM\Entity */ class Post { /** * Use the storable file trait */ use StorableTrait; // ... /** * Set my file * * @param \Symfony\Component\HttpFoundation\File\UploadedFile $file * @return $this */ public function setMyFile(UploadedFile $file = null) { $this->setUploadedFile($file); return $this; } }
然后您可以将新名称添加到表单类型中,如下所示
// ... /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('title', 'text') ->add('my_file', 'file', [ 'required' => false, ]) ; } // ...
事件
存储处理程序,它是 Doctrine 实体生命周期的组成部分,在文件存储活动的边缘触发多个事件。这些事件包括
- ashleydawson.doctrine_flysystem_bundle.pre_store
- 在文件写入文件系统之前触发
- ashleydawson.doctrine_flysystem_bundle.post_store
- 在文件写入文件系统之后触发
- ashleydawson.doctrine_flysystem_bundle.pre_delete
- 在文件从文件系统中删除之前触发
- ashleydawson.doctrine_flysystem_bundle.post_delete
- 在文件从文件系统中删除之后触发
这些事件可以在命名空间 AshleyDawson\DoctrineFlysystemBundle\Event\StorageEvents
中找到。
这些事件的良好用例是在写入之前更改表单的任何详细信息,例如(在 Symfony 控制器中)
// Replace the file storage path with a random md5 hash directory structure, name and file extension $this->get('event_dispatcher')->addListener(StorageEvents::PRE_STORE, function (StoreEvent $event) { // Build a directory structure like "af/9e" $fileStoragePath = implode('/', str_split(substr(md5(mt_rand()), 0, 4), 2)); $event->setFileStoragePath(sprintf('/%s/%s.%s', $fileStoragePath, md5(mt_rand()), $event->getUploadedFile()->getClientOriginalExtension())); });
当然,这是一个简单的示例 - 但它确实展示了如何更改文件(或文件的元信息)。在上面的示例中,我正在构建存储路径的哈希目录结构。类似于以下内容
/af/9e/2997f54d953111d222c00a0b6ed94a50.gif
注意:请不要将上面的示例作为生产解决方案使用,因为存在文件名冲突的可能性。
还可能是一个好主意,而不是像我上面那样使用基于闭包的实现,而是安装一个订阅者。您应该始终努力提供促进单一职责原则的系统!
可选配置
以下方式定义了可选配置参数
# app/config/config.yml ashley_dawson_doctrine_flysystem: delete_old_file_on_update: true # Default is true
将 delete_old_file_on_update
设置为 false 将意味着在实体使用新文件更新时,将与实体关联的旧文件删除。
覆盖字段映射
当实体使用 StorableTrait 时,映射了多个用于存储文件元数据的字段。如果您需要更改这些映射,可以通过实现 AshleyDawson\DoctrineFlysystemBundle\ORM\Mapping\StorableFieldMapperInterface
并覆盖此包中提供的映射来做到这一点。这将允许您为每个字段定义自己的映射策略。例如
<?php namespace Acme\DemoBundle\ORM\Flysystem\Mapping; use AshleyDawson\DoctrineFlysystemBundle\ORM\Mapping\StorableFieldMapperInterface; use Doctrine\ORM\Mapping\ClassMetadataInfo; /** * Class MyStorableFieldMapper * * @package Acme\DemoBundle\ORM\Flysystem\Mapping */ class MyStorableFieldMapper implements StorableFieldMapperInterface { /** * {@inheritdoc} */ public function mapFields(ClassMetadataInfo $classMetadata) { $classMetadata ->mapField([ 'fieldName' => 'fileName', 'columnName' => 'file_name', 'type' => 'string', 'length' => 255, 'nullable' => true, ]) ; $classMetadata ->mapField([ 'fieldName' => 'fileStoragePath', 'columnName' => 'file_storage_path', 'type' => 'string', 'length' => 255, 'nullable' => true, ]) ; $classMetadata ->mapField([ 'fieldName' => 'fileSize', 'columnName' => 'file_size', 'type' => 'integer', 'nullable' => true, ]) ; $classMetadata ->mapField([ 'fieldName' => 'fileMimeType', 'columnName' => 'file_mime_type', 'type' => 'string', 'length' => 60, 'nullable' => true, ]) ; } }
然后只需配置服务容器以使用您的映射器
# app/config/parameters.yml ashley_dawson.doctrine_flysystem.storable_field_mapper.class: Acme\DemoBundle\ORM\Flysystem\Mapping\MyStorableFieldMapper