arxy/files

此包的最新版本(5.1.4)没有可用的许可证信息。

维护者

详细信息

github.com/Warxcell/files

源代码

问题

安装: 6,330

依赖关系: 0

建议者: 0

安全: 0

星标: 16

关注者: 3

分支: 0

公开问题: 1

类型:symfony-bundle

5.1.4 2024-05-21 12:36 UTC

This package is auto-updated.

Last update: 2024-09-21 13:15:58 UTC


README

提供方便的文件管理(具有元数据持久层)。

  • 使用 FlySystem 进行文件管理(这允许您使用现有的适配器在任何地方保存文件)。
  • 在数据库中持久化文件信息
  • 使用校验和(md5)来防止重复上传(从而节省空间)。如果找到相同的文件,则将其重用。
  • 自动挂钩管理文件(在实体持久化时将上传文件,在实体删除时将删除文件)。
  • 处理文件的不同命名策略。

PHP CodeSniffer

PhpUnit

Psalm Static analysis

用法

配置

创建将保存文件的对象

<?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。

从控制器中提供文件

  1. 使用控制器提供

创建将提供文件的控制器。

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

向路径解析器发送附加参数。

好的,我们已经生成了文件的路径,但如果我们想以不同的方式表示相同的文件怎么办?显然,我们目前不能这样做。让我们改变一下!假设我们需要强制执行不同的下载名称。

  1. 我们首先创建装饰文件。
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;
    }
}
  1. 然后我们创建/装饰路径解析器
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());
    }
}
  1. 然后我们可以像平常一样使用路径解析器
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扩展

  1. Arxy\FilesBundle\Twig\FilesExtensions
  • int 12345|format_bytes(int $precision = 2) - 以kb、mb等格式化字节数。
  • Arxy\FilesBundle\Model\File $file|file_content - 返回文件的內容。
  1. Arxy\FilesBundle\Twig\PathResolverExtension
  • file_path(Arxy\FilesBundle\Model\File $file) - 使用路径解析器返回文件的下载路径。

LiipImagine

如果您需要为文件生成缩略图,则可以使用与 LiipImagineBundle 的内置集成。

  1. 设置LiipImagineBundle。
  2. Arxy\FilesBundle\LiipImagine\FileFilterPathResolver 注册为服务。
  3. 按照以下方式使用服务:$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种方法启用它

  1. 同步生成:Arxy\FilesBundle\Preview\PreviewGeneratorListener

  2. 使用 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.* 的发布以便能够修复此问题。