arxy / files
Requires
- php: ^8.0
- gabrielelana/byte-units: ^0.5.0
- league/mime-type-detection: ^1.7
Requires (Dev)
- aws/aws-sdk-php: *
- doctrine/doctrine-bundle: ^2.3
- doctrine/orm: *
- imagine/imagine: ^1.2
- infection/infection: ^0.21.4
- league/flysystem: ^2.0 | ^3.0
- league/flysystem-bundle: ^2.0
- league/flysystem-memory: ^2.0
- liip/imagine-bundle: ^2.6
- microsoft/azure-storage-blob: *
- phpunit/phpunit: ^9.5
- slevomat/coding-standard: ^7.0
- squizlabs/php_codesniffer: *
- symfony/asset: *
- symfony/cache: *
- symfony/dependency-injection: ^5.2
- symfony/form: *
- symfony/http-foundation: *
- symfony/http-kernel: *
- symfony/messenger: *
- symfony/symfony: ^4.4 | ^5.2
- symfony/uid: *
- symfony/validator: *
- twig/twig: *
- vimeo/psalm: ^4.7
Suggests
- aws/aws-sdk-php: Generate file urls for files hosted on AWS S3
- doctrine/orm: Use Doctrine ORM as persistence layer
- imagine/imagine: Use ImagePreviewGenerator
- league/flysystem: Use FlySystem Storage to store contents of file
- liip/imagine-bundle: Generate image thumbnails
- microsoft/azure-storage-blob: Generate file urls for files hosted on Microsoft Azure Blob Storage
- symfony/event-dispatcher: Usage of events.
- symfony/form: Integrate file upload with forms
- symfony/messenger: Generate Previews asynchronous.
- symfony/uid: Required to use UuidV5Strategy/UuidV4Strategy Naming Strategy
- symfony/validator: Validate files against constraints
- twig/twig: Use Arxy\Files\Twig\FilesExtension::formatBytes to get formatted KiB/MiB/GB instead. Also for form template
README
提供方便的文件管理(具有元数据持久层)。
- 使用 FlySystem 进行文件管理(这允许您使用现有的适配器在任何地方保存文件)。
- 在数据库中持久化文件信息
- 使用校验和(md5)来防止重复上传(从而节省空间)。如果找到相同的文件,则将其重用。
- 自动挂钩管理文件(在实体持久化时将上传文件,在实体删除时将删除文件)。
- 处理文件的不同命名策略。
用法
配置
创建将保存文件的对象
<?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity() * @ORM\Table() */ class File extends \Arxy\FilesBundle\Entity\File { /** * @var int|null * @ORM\Id() * @ORM\Column(type="integer") * @ORM\GeneratedValue() */ protected $id; /** * @return int|null */ public function getId(): ?int { return $this->id; } /** * @param int|null $id */ public function setId(?int $id): void { $this->id = $id; } }
如果您想使用可嵌入对象而不是实体作为文件对象
<?php namespace App\Entity; use Arxy\FilesBundle\Model\File;use Doctrine\ORM\Mapping as ORM; use Arxy\FilesBundle\Entity\EmbeddableFile; /** * @ORM\Entity() * @ORM\Table() */ class News { /** @ORM\Embedded(class=EmbeddableFile::class) */ private ?EmbeddableFile $image = null; public function getImage(): ?File { return $this->image; } public function setImage(?File $file) { $this->image = $file; } }
创建存储库。
<?php namespace App\Repository; use Arxy\FilesBundle\Repository; use Doctrine\ORM\EntityRepository; use \Arxy\FilesBundle\Repository\ORM; class FileRepository extends EntityRepository implements Repository { use ORM; }
services: Arxy\FilesBundle\NamingStrategy\SplitHashStrategy: ~ flysystem: storages: in_memory: adapter: 'memory' arxy_files: managers: public: driver: orm class: 'App\Entity\File' storage: 'in_memory' naming_strategy: 'Arxy\FilesBundle\NamingStrategy\SplitHashStrategy' repository: 'App\Repository\FileRepository'
或使用纯服务
services: files_local_adapter: class: League\Flysystem\Local\LocalFilesystemAdapter arguments: - "/directory/for/files/" League\Flysystem\Filesystem: - "@files_local_adapter" League\Flysystem\FilesystemOperator: alias: League\Flysystem\Filesystem Arxy\FilesBundle\Twig\FilesExtension: tags: - { name: twig.extension } Arxy\FilesBundle\NamingStrategy\IdToPathStrategy: ~ Arxy\FilesBundle\NamingStrategy\AppendExtensionStrategy: - '@Arxy\FilesBundle\NamingStrategy\IdToPathStrategy' Arxy\FilesBundle\NamingStrategy: alias: Arxy\FilesBundle\NamingStrategy\AppendExtensionStrategy Arxy\FilesBundle\Storage\FlysystemStorage: ~ Arxy\FilesBundle\Storage: alias: 'Arxy\FilesBundle\Storage\FlysystemStorage' Arxy\FilesBundle\Manager: $class: 'App\Entity\File' Arxy\FilesBundle\ManagerInterface: alias: Arxy\FilesBundle\Manager Arxy\FilesBundle\EventListener\DoctrineORMListener: arguments: [ "@Arxy\\FilesBundle\\ManagerInterface" ] # This can be omit, if using autowiring. tags: - { name: doctrine.event_listener, event: 'postPersist' } - { name: doctrine.event_listener, event: 'preRemove' } Arxy\FilesBundle\Form\Type\FileType: arguments: [ "@Arxy\\FilesBundle\\ManagerInterface" ] # This can be omit, if using autowiring. tags: # This can be omit, if using autowiring. - { name: form.type }
或使用纯PHP
$adapter = new \League\Flysystem\Local\LocalFilesystemAdapter; $filesystem = new \League\Flysystem\Filesystem($adapter); $storage = new \Arxy\FilesBundle\Storage\FlysystemStorage($filesystem); $namingStrategy = new \Arxy\FilesBundle\NamingStrategy\SplitHashStrategy(); $repository = new FileRepository(); $fileManager = new \Arxy\FilesBundle\Manager(\App\Entity\File::class, $storage, $namingStrategy, $repository);
上传文件
$file = new \SplFileInfo($pathname); $fileEntity = $fileManager->upload($file); $file = $request->files->get('file'); $fileEntity = $fileManager->upload($file); $entityManager->persist($fileEntity); $entityManager->flush();
在嵌入式情况下
$file = new \SplFileInfo($pathname); $embeddableFile = $fileManager->upload($file); $news = new \App\Entity\News(); $news->setImage($embeddableFile); $entityManager->persist($news); $entityManager->flush();
请注意,文件实际上不会移动到其最终位置,直到文件持久化到数据库中,这是通过监听器完成的。(例如 Arxy\FilesBundle\DoctrineORMListener)
使用表单类型上传
$formBuilder->add( 'image', FileType::class, [ 'required' => false, 'constraints' => [ConstraintsOnEntity] 'input_options' => [ 'attr' => [ 'accept' => 'image/*', ], 'constraints' => [ SymfonyConstraintsOnFiles ] ], ] );
读取文件内容
$file = $entityManager->find(File::class, 1); $content = $fileManager->read($file);
读取流
$file = $entityManager->find(File::class, 1); $fileHandle = $fileManager->readStream($file);
此包还包含用于上传和验证文件的表单和约束。您可以编写自己的命名策略,以确定在文件系统上创建文件的方式。您甚至可以编写自己的 Flysystem 文件系统后端并将其用于此处。
目前,仅支持 Doctrine ORM 作为持久化层。请随意提交有关其他持久化层的 PR。
从控制器中提供文件
- 使用控制器提供
创建将提供文件的控制器。
<?php declare(strict_types=1); namespace App\Controller; use App\Entity\File; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Routing\Annotation\Route; use Arxy\FilesBundle\Utility\DownloadUtility; use Symfony\Component\HttpFoundation\Response; class FileController extends AbstractController { /** * @Route(path="/file/{id}", name="file_download") */ public function download( string $id, EntityManagerInterface $em, DownloadUtility $downloadUtility ): Response { $file = $em->getRepository(File::class)->findOneBy( [ 'md5Hash' => $id, ] ); if ($file === null) { throw $this->createNotFoundException('File not found'); } return $downloadUtility->createResponse($file); } }
如果您想强制使用不同的下载名称,您可以使用 Arxy\FilesBundle\Utility\DownloadableFile
装饰文件
<?php declare(strict_types=1); namespace App\Controller; use App\Entity\File; use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Routing\Annotation\Route; use Arxy\FilesBundle\Utility\DownloadUtility; use Arxy\FilesBundle\Utility\DownloadableFile; use Symfony\Component\HttpFoundation\Response; class FileController extends AbstractController { /** * @Route(path="/file/{id}", name="file_download") */ public function download( string $id, EntityManagerInterface $em, DownloadUtility $downloadUtility ): Response { $file = $em->getRepository(File::class)->findOneBy( [ 'md5Hash' => $id, ] ); if ($file === null) { throw $this->createNotFoundException('File not found'); } return $downloadUtility->createResponse(new DownloadableFile($file, 'my_name.jpg', false, new \DateTimeImmutable('date of cache expiry'))); } }
提供
您可能想使用 LiipImagineBundle 或 CDN 解决方案,或者甚至控制器。
直接
如果您想直接使用 CDN 提供文件,您可以使用路径解析器 + 正规化器
<?php declare(strict_types=1); namespace App\Serializer; use App\Entity\File; use Arxy\FilesBundle\PathResolver; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; class FileNormalizer implements NormalizerInterface { private ObjectNormalizer $objectNormalizer; private PathResolver $pathResolver; public function __construct( ObjectNormalizer $objectNormalizer, PathResolver $pathResolver ) { $this->objectNormalizer = $objectNormalizer; $this->pathResolver = $pathResolver; } public function normalize($object, $format = null, array $context = array()) { assert($object instanceof File); $data = $this->objectNormalizer->normalize($object, $format, $context); $data['url'] = $this->pathResolver->getPath($object); return $data; } public function supportsNormalization($data, $format = null) { return $data instanceof File; } }
/** * @var string * @Groups({"file_read"}) */ private string $url = null; public function getUrl(): array { return $this->url; } public function setUrl(string $url): void { $this->url = $url; }
您将收到以下 JSON 作为响应
{ "id": 145, "mimeType": "application/pdf", "size": 532423, "url": "https://example.com/link-to-image.pdf" }
LiipImagineBundle
如果您想与 LiipImagineBundle 一起使用它,您可能需要添加以下内容
/** * @var array * @Groups({"file_read"}) */ private $formats = []; public function getFormats(): array { return $this->formats; } public function setFormats(array $formats): void { $this->formats = $formats; }
并从事件监听器、ORM 监听器或序列化规范化器中填充这些内容。
以下是用序列化规范化器示例
<?php declare(strict_types=1); namespace App\Serializer; use App\Entity\File; use Arxy\FilesBundle\LiipImagine\FileFilter;use Arxy\FilesBundle\LiipImagine\FileFilterPathResolver;use Liip\ImagineBundle\Imagine\Filter\FilterConfiguration; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; class FileNormalizer implements NormalizerInterface { private ObjectNormalizer $objectNormalizer; private FileFilterPathResolver $fileFilterPathResolver; private FilterConfiguration $filterConfiguration; public function __construct( ObjectNormalizer $objectNormalizer, FileFilterPathResolver $fileFilterPathResolver, FilterConfiguration $filterConfiguration ) { $this->objectNormalizer = $objectNormalizer; $this->fileFilterPathResolver = $fileFilterPathResolver; $this->filterConfiguration = $filterConfiguration; } public function normalize($object, $format = null, array $context = array()) { assert($object instanceof \Arxy\FilesBundle\Model\File); $data = $this->objectNormalizer->normalize($object, $format, $context); $data['formats'] = array_reduce( array_keys($this->filterConfiguration->all()), function ($array, $filter) use ($object) { $array[$filter] = $this->fileFilterPathResolver->getUrl(new FileFilter($object, $filter)); return $array; }, [] ); return $data; } public function supportsNormalization($data, $format = null) { return $data instanceof \Arxy\FilesBundle\Model\File; } }
您将收到以下 JSON 作为响应
{ "id": 145, "formats": { "squared_thumbnail": "https:\/\/host.com\/media\/cache\/resolve\/squared_thumbnail\/1\/4\/5\/145" } }
命名策略
命名策略负责将文件对象转换为文件路径。存在几种内置策略
DateStrategy
使用文件的 createdAt 属性。默认格式:Y/m/d/hash。示例:2021/05/17/59aeac36ae75786be1b573baad0e77c0
SplitHashStrategy
使用文件的 md5hash 并将其分成块。示例:`098f6bcd4621d373cade4e832627b4f6` 将产生 `098f6bcd/4621d373/cade4e83/2627b4f6/098f6bcd4621d373cade4e832627b4f6`
UuidV5Strategy
使用 UUID V5 生成文件的哈希。它由命名空间(可配置)和值(使用文件的 md5Hash)组成。
AppendExtensionStrategy
添加文件扩展名(.jpg、.pdf 等)的装饰器。
DirectoryPrefixStrategy
为其他命名策略生成的目录添加前缀的装饰器。
NullDirectoryStrategy
始终返回 null 目录的装饰器。
PersistentPathStrategy
使用文件中持久化的路径名称。如果您想为每个文件生成完全随机的路径(例如 UUID v4)或您只是想出于某种原因保留文件的路径,则非常有用。它期望 Arxy\FilesBundle\Model\PathAwareFile
的实例。您负责处理路径本身。您可以通过自定义 Arxy\FilesBundle\ModelFactory
(推荐)或使用内置的事件监听器(例如 Arxy\FilesBundle\EventListener\PathAwareListener
)来完成此操作。
UUID V4 Strategy
生成随机路径。
在命名策略之间迁移。
注册迁移器服务和命令
services: Arxy\FilesBundle\Migrator: $filesystem: '@League\Flysystem\FilesystemOperator' $oldNamingStrategy: '@old_naming_strategy' $newNamingStrategy: '@new_naming_strategy' Arxy\FilesBundle\Command\MigrateNamingStrategyCommand: $migrator: '@Arxy\FilesBundle\Migrator' $repository: '@repository'
然后运行它。
bin/console arxy:files:migrate-naming-strategy
PathResolver:用于生成浏览器URL以访问文件。存在少量内置解析器
AssetsPathResolver
Arxy\FilesBundle\PathResolver\AssetsPathResolver: $manager: '@Arxy\FilesBundle\ManagerInterface' $package: 'packageName' # https://symfony.com.cn/doc/current/components/asset.html#asset-packages Arxy\FilesBundle\PathResolver: alias: Arxy\FilesBundle\PathResolver\AssetsPathResolver
AwsS3PathResolver
Aws\S3\S3Client: class: Aws\S3\S3Client arguments: $args: region: 'region' version: 'version' credentials: key: 'key' secret: 'secret' Aws\S3\S3ClientInterface: alias: Aws\S3\S3Client Arxy\FilesBundle\PathResolver\AwsS3PathResolver: arguments: $s3Client: '@Aws\S3\S3ClientInterface' $bucket: 'bucket-name' $manager: '@Arxy\FilesBundle\ManagerInterface' Arxy\FilesBundle\PathResolver: alias: Arxy\FilesBundle\PathResolver\AwsS3PathResolver
AzureBlobStoragePathResolver
MicrosoftAzure\Storage\Blob\BlobRestProxy: factory: [ 'MicrosoftAzure\Storage\Blob\BlobRestProxy', 'createBlobService' ] arguments: $connectionString: 'DefaultEndpointsProtocol=https;AccountName=xxxxxxxx;EndpointSuffix=core.windows.net' Arxy\FilesBundle\PathResolver\AzureBlobStoragePathResolver: arguments: $client: '@MicrosoftAzure\Storage\Blob\BlobRestProxy' $container: 'container-name' $manager: '@Arxy\FilesBundle\ManagerInterface' Arxy\FilesBundle\PathResolver: alias: Arxy\FilesBundle\PathResolver\AzureBlobStoragePathResolver
AzureBlobStorageSASPathResolver
- 装饰器接受
Arxy\FilesBundle\PathResolver\AzureBlobStoragePathResolver
并添加 SAS签名
创建 AzureBlobStorageSASParametersFactory
实例,该实例将负责创建签名参数。
class MyFactory implements \Arxy\FilesBundle\PathResolver\AzureBlobStorageSASParametersFactory { public function create(\Arxy\FilesBundle\Model\File $file) : \Arxy\FilesBundle\PathResolver\AzureBlobStorageSASParameters { return new \Arxy\FilesBundle\PathResolver\AzureBlobStorageSASParameters( new \DateTimeImmutable('+10 minutes'), ); } }
MicrosoftAzure\Storage\Blob\BlobSharedAccessSignatureHelper: arguments: $accountName: 'account-name' $accountKey: 'account-key' MyFactory: ~ Arxy\FilesBundle\PathResolver\AzureBlobStorageSASParametersFactory: alias: '@MyFactory' Arxy\FilesBundle\PathResolver\AzureBlobStorageSASPathResolver: arguments: $pathResolver: '@Arxy\FilesBundle\PathResolver\AzureBlobStoragePathResolver' $signatureHelper: '@MicrosoftAzure\Storage\Blob\BlobSharedAccessSignatureHelper' $factory: '@Arxy\FilesBundle\PathResolver\AzureBlobStorageSASParametersFactory' Arxy\FilesBundle\PathResolver: alias: Arxy\FilesBundle\PathResolver\AzureBlobStorageSASPathResolver
CachePathResolver
用于缓存装饰的PathResolver的结果。例如,与AwsS3PathResolver结合使用时,获取上传文件的路径需要调用API。此解析器将缓存来自AWS S3服务器的响应,下次需要文件路径时,将从缓存中返回。使用 https://symfony.com.cn/doc/current/components/cache.html
Arxy\FilesBundle\PathResolver\AwsS3PathResolver: arguments: $bucket: '%env(AWS_S3_BUCKET)%' $manager: '@Arxy\FilesBundle\ManagerInterface' Arxy\FilesBundle\PathResolver\CachePathResolver: arguments: $pathResolver: '@Arxy\FilesBundle\PathResolver\AwsS3PathResolver' $cache: '@cache.app' Arxy\FilesBundle\PathResolver: alias: Arxy\FilesBundle\PathResolver\CachePathResolver
DelegatingPathResolver
当您的系统有多个文件实体时使用
Arxy\FilesBundle\PathResolver\DelegatingPathResolver: $resolvers: 'App\Entity\File': '@path_resolver' 'App\Entity\OtherFile': '@other_path_resolver'
您还可以使用PathResolverManager装饰器将Manager和PathResolver合并为一个,以便您可以为一个实例使用两种操作
Arxy\FilesBundle\PathResolverManager: $manager: '@manager' $pathResolver: '@path_resolver' Arxy\FilesBundle\ManagerInterface: alias: Arxy\FilesBundle\PathResolverManager Arxy\FilesBundle\PathResolver: alias: Arxy\FilesBundle\PathResolverManager
还有DelegatingManager,它可以作为支持不同类的路由器使用
Arxy\FilesBundle\DelegatingManager: $managers: [ '@manager_1', '@manager_2' ]
然后您可以这样做:$manager->getManagerFor(File::class)->upload($file)
。注意:如果直接执行 $manager->upload($file)
- 它将调用第一个管理器的上传方法。读取更容易:只需传递 $file
,它将确定正确的内部管理器。 $manager->read($file)
向路径解析器发送附加参数。
好的,我们已经生成了文件的路径,但如果我们想以不同的方式表示相同的文件怎么办?显然,我们目前不能这样做。让我们改变一下!假设我们需要强制执行不同的下载名称。
- 我们首先创建装饰文件。
class VirtualFile extends \Arxy\FilesBundle\Model\DecoratedFile { private ?string $downloadFilename = null; public function setDownloadFilename(string $filename) { $this->downloadFilename = $filename; } public function getDownloadFilename(): ?string { return $this->downloadFilename; } }
- 然后我们创建/装饰路径解析器
class VirtualFilePathResolver implements \Arxy\FilesBundle\PathResolver { public function getPath(\Arxy\FilesBundle\Model\File $file): string { assert($file instanceof VirtualFile); return sprintf('url?download_filename=%s', $file->getDownloadFilename()); } }
- 然后我们可以像平常一样使用路径解析器
public function someAction(\Arxy\FilesBundle\PathResolver $pathResolver) { $virtualFile = new \Arxy\FilesBundle\Tests\VirtualFile($file); $virtualFile->setDownloadFilename('this_file_is_renamed_during_download.jpg'); $downloadUrl = $pathResolver->getPath($virtualFile); }
Twig扩展
- Arxy\FilesBundle\Twig\FilesExtensions
int 12345|format_bytes(int $precision = 2)
- 以kb、mb等格式化字节数。Arxy\FilesBundle\Model\File $file|file_content
- 返回文件的內容。
- Arxy\FilesBundle\Twig\PathResolverExtension
file_path(Arxy\FilesBundle\Model\File $file)
- 使用路径解析器返回文件的下载路径。
LiipImagine
如果您需要为文件生成缩略图,则可以使用与 LiipImagineBundle 的内置集成。
- 设置LiipImagineBundle。
- 将
Arxy\FilesBundle\LiipImagine\FileFilterPathResolver
注册为服务。 - 按照以下方式使用服务:
$pathResolver->getPath(new \Arxy\FilesBundle\LiipImagine\FileFilter($file, 'filterName'));
与 API Platform 一起使用
上传
<?php declare(strict_types=1); namespace App\Controller\ApiPlatform; use Arxy\FilesBundle\Manager; use Arxy\FilesBundle\Model\File; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; final class Upload { private Manager $fileManager; public function __construct(Manager $fileManager) { $this->fileManager = $fileManager; } public function __invoke(Request $request): File { $uploadedFile = $request->files->get('file'); if (!$uploadedFile) { throw new BadRequestHttpException('"file" is required'); } return $this->fileManager->upload($uploadedFile); } }
<?php declare(strict_types=1); namespace App\Entity; use ApiPlatform\Core\Annotation\ApiResource; use App\Controller\ApiPlatform\Upload; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\Groups; /** * @ORM\Entity * @ORM\Table(name="files") * @ApiResource( * iri="http://schema.org/MediaObject", * normalizationContext={ * "groups"={"file_read"} * }, * collectionOperations={ * "post"={ * "controller"=Upload::class, * "deserialize"=false, * "validation_groups"={"Default"}, * "openapi_context"={ * "requestBody"={ * "content"={ * "multipart/form-data"={ * "schema"={ * "type"="object", * "properties"={ * "file"={ * "type"="string", * "format"="binary" * } * } * } * } * } * } * } * } * }, * itemOperations={ * "get" * } * ) */ class File extends \Arxy\FilesBundle\Entity\File { /** * @var int|null * * @ORM\Id * @ORM\Column(type="integer", nullable=false) * @ORM\GeneratedValue * @Groups({"file_read"}) */ protected ?int $id = null; public function getId(): ?int { return $this->id; } }
事件
PostUpload
Arxy\FilesBundle\Events\PostUpload
事件在File对象创建后立即调用。如果找到现有文件并重新使用,则不会调用该事件。此时文件位于本地文件系统。
PreMove
Arxy\FilesBundle\Events\PreMove
事件在File对象移动到其最终位置之前调用。此时文件仍然位于本地。因此,ManagerInterface::getPathname()
返回本地文件路径。
PostMove
Arxy\FilesBundle\Events\PostMove
事件在File对象移动到其最终位置之后调用。此时文件位于FlySystem中。因此,ManagerInterface::getPathname()
返回命名策略生成的文件路径。
PreUpdate
Arxy\FilesBundle\Events\PreUpdate
事件在通过写入、写入流更新File对象之前调用。
PostUpdate
Arxy\FilesBundle\Events\PostUpdate
事件在通过写入、写入流更新File对象之后调用。
PreRemove
Arxy\FilesBundle\Events\PreRemove
事件在文件从文件系统中删除之前被调用。
预览
存在一个用于生成文件预览的子系统:它生成预览并将其保存为另一个文件。有2种方法启用它
-
同步生成:
Arxy\FilesBundle\Preview\PreviewGeneratorListener
-
使用 Symfony Messenger 异步生成:
Arxy\FilesBundle\Preview\GeneratePreviewMessageHandler
Arxy\FilesBundle\Preview\PreviewGeneratorMessengerListener
然后注册通用服务
Imagine\Gd\Imagine: ~ Arxy\FilesBundle\Preview\ImagePreviewGenerator: $manager: '@public' <-- manager of files. $imagine: '@Imagine\Gd\Imagine' Arxy\FilesBundle\Preview\Dimension: $width: 250 <- width of generated thumbnail $height: 250 <- height of generated thumbnail Arxy\FilesBundle\Preview\DimensionInterface: '@Arxy\FilesBundle\Preview\Dimension' Arxy\FilesBundle\Preview\PreviewGenerator: $manager: '@preview' <- manager of previews $generators: - '@Arxy\FilesBundle\Preview\ImagePreviewGenerator'
目前,只有图像预览生成器存在。您可以添加自己的图像预览生成器。只需实现 Arxy\FilesBundle\Preview\PreviewGeneratorInterface
。
已知问题
- 如果在事务中删除文件并且事务回滚 - 文件将被删除。我正在等待 DBAL 3.2.* 的发布以便能够修复此问题。