68publishers / file-storage
基于 Flysystem 的文件管理,并集成到 Nette 框架中。
v1.1.3
2024-08-06 02:38 UTC
Requires
- php: ^8.1
- ext-fileinfo: *
- ext-json: *
- league/flysystem: ^3.12
- psr/log: ^1.1 || ^2.0 || ^3.0
Requires (Dev)
- 68publishers/doctrine-bridge: ^1.0
- doctrine/dbal: ^2.13.1 || ^3.1.1
- fig/log-test: ^1.1
- friendsofphp/php-cs-fixer: ^3.13
- kubawerlos/php-cs-fixer-custom-fixers: ^3.13
- latte/latte: ^3.0
- league/flysystem-memory: ^3.10
- mockery/mockery: ^1.5
- nette/application: ^3.1.8
- nette/bootstrap: ^3.1
- nette/di: ^3.0.10
- nette/tester: ^2.4.3
- phpstan/phpstan: ^1.9
- phpstan/phpstan-nette: ^1.1
- roave/security-advisories: dev-latest
- symfony/console: ^5.0 | ^6.0
Suggests
- 68publishers/doctrine-bridge: For an integration of a custom Doctrine types into the Nette.
- latte/latte: For usage with Latte templates.
- nette/di: For an integration with Nette Framework.
- symfony/console: If you want to use a console commands.
Conflicts
- 68publishers/doctrine-bridge: <1.0
- latte/latte: <3.0
- nette/di: <3.0.10
- nette/schema: <1.1
- symfony/console: <5.0
README
📁 基于 Flysystem 的文件管理,并集成到 Nette 框架。
安装
使用 Composer 安装 68publishers/file-storage 是最佳方式
$ composer require 68publishers/file-storage
Nette 框架集成
使用此扩展,您可以注册更多具有不同根目录、文件系统适配器等的存储。第一个注册的存储也被视为默认存储。
配置示例
extensions: 68publishers.file_storage: SixtyEightPublishers\FileStorage\Bridge\Nette\DI\FileStorageExtension 68publishers.file_storage: storages: default: config: base_path: /data/files filesystem: adapter: League\Flysystem\Local\LocalFilesystemAdapter(%wwwDir%/data/files) config: [] # an optional config for filesystem adapter assets: path/to/file.png: my/file.png # single file copying path/to/directory: my-directory # copy whole directory s3: config: host: https://my-bucket.s3.amazonaws.com filesystem: adapter: League\Flysystem\AwsS3V3\AwsS3V3Adapter(@s3client, my-bucket)
存储配置选项
基本用法
生成的 DI 容器将包含自动注入的 FileStorageProviderInterface
和 FileStorageInterface
(默认存储)服务。
use Nette\DI\Container; use SixtyEightPublishers\FileStorage\FileStorageInterface; use SixtyEightPublishers\FileStorage\FileStorageProviderInterface; /** @var Container $container */ $defaultStorage = $container->getByType(FileStorageInterface::class); $provider = $container->getByType(FileStorageProviderInterface::class); $defaultStorage = $provider->get(); # or $defaultStorage = $provider->get('default'); $s3storage = $provider->get('s3');
持久化文件
use SixtyEightPublishers\FileStorage\FileStorageInterface; /** @var FileStorageInterface $storage */ # Create a resource from file or url: $resource = $storage->createResourceFromFile( $storage->createPathInfo('test/invoice.pdf'), __DIR__ . '/path/to/invoice.pdf' ); $storage->save($resource); # Create resource from file that is stored in storage: $resource = $storage->createResource( $storage->createPathInfo('test/invoice.pdf') ); # copy to the new location $storage->save($resource->withPathInfo( $storage->createPathInfo('test/invoice-2.pdf') ));
检查文件是否存在
use SixtyEightPublishers\FileStorage\FileStorageInterface; /** @var FileStorageInterface $storage */ if ($storage->exists($storage->createPathInfo('test/invoice.pdf'))) { echo 'file exists!'; }
删除文件
use SixtyEightPublishers\FileStorage\FileStorageInterface; /** @var FileStorageInterface $storage */ $storage->delete($storage->createPathInfo('test/invoice.pdf'));
创建指向文件的链接
use SixtyEightPublishers\FileStorage\FileStorageInterface; /** @var FileStorageInterface $storage */ # /data/files/test/invoice.pdf echo $storage->link($storage->createPathInfo('test/invoice.pdf')); # or $fileInfo = $storage->createFileInfo($storage->createPathInfo('test/invoice.pdf')); echo $fileInfo->link();
清理存储
use Nette\DI\Container; use SixtyEightPublishers\FileStorage\FileStorageProviderInterface; use SixtyEightPublishers\FileStorage\Cleaner\StorageCleanerInterface; /** @var Container $container */ $cleaner = $container->getByType(StorageCleanerInterface::class); $provider = $container->getByType(FileStorageProviderInterface::class); $storage = $provider->get('default'); # get files count in the specific namespace: $cleaner->getCount($storage->getFilesystem(), [ StorageCleanerInterface::OPTION_NAMESPACE => 'test', ]); # get files count in the whole storage: $cleaner->getCount($storage->getFilesystem()); # remove files in the specific namespace: $cleaner->clean($storage->getFilesystem(), [ StorageCleanerInterface::OPTION_NAMESPACE => 'test', ]); # clean the whole storage: $cleaner->clean($storage->getFilesystem());
资产复制
use Nette\DI\Container; use SixtyEightPublishers\FileStorage\FileStorageProviderInterface; use SixtyEightPublishers\FileStorage\Asset\AssetsCopierInterface; /** @var Container $container */ $copier = $container->getByType(AssetsCopierInterface::class); $provider = $container->getByType(FileStorageProviderInterface::class); # Copies assets defined in the configuration $copier->copy($provider->get('default')); $copier->copy($provider->get('s3'));
可以在每个存储的配置下分别定义资产,但编译器扩展可以定义其他资产
use Nette\DI\CompilerExtension; use SixtyEightPublishers\FileStorage\Bridge\Nette\DI\Assets; use SixtyEightPublishers\FileStorage\Bridge\Nette\DI\AssetsProviderInterface; final class MyCompilerExtension extends CompilerExtension implements AssetsProviderInterface { public function provideAssets() : array { return [ new Assets('s3', [ 'path/to/file1.jpeg' => 'namespace/file1.jpeg', 'path/to/file2.jpeg' => 'namespace/file2.jpeg', ]), ]; } }
与 Doctrine ORM 一起使用
此包提供自定义 Doctrine DBAL 类型 file_info
。您可以手动注册它,方法如下
use Doctrine\DBAL\Types\Type; use SixtyEightPublishers\FileStorage\FileStorageProviderInterface; use SixtyEightPublishers\FileStorage\Bridge\Doctrine\DbalType\FileInfoType; /** @var FileStorageProviderInterface $fileStorageProvider */ Type::addType(FileInfoType::NAME, FileInfoType::class); # this line is important: Type::getType(FileInfoType::NAME)->setFileStorageProvider($fileStorageProvider);
或者,您可以使用编译器扩展 FileStorageDoctrineExtension
。该扩展需要集成包 68publishers/doctrine-bridge。
extensions: 68publishers.file_storage.doctrine: SixtyEightPublishers\FileStorage\Bridge\Nette\DI\FileStorageDoctrineExtension 68publishers.file_storage.doctrine: type_name: file_info # default
示例实体和持久化
use Doctrine\ORM\Mapping as ORM; use SixtyEightPublishers\FileStorage\FileInfoInterface; /** * @ORM\Entity */ class File { # ID and other columns /** * @ORM\Column(type="file_info") */ private FileInfoInterface $source; public function __construct(FileInfoInterface $source) { $this->source = $source; } public function getSource(): FileInfoInterface { return $this->source; } }
use Doctrine\ORM\EntityManagerInterface; use SixtyEightPublishers\FileStorage\FileStorageInterface; /** @var EntityManagerInterface $em */ /** @var FileStorageInterface $storage */ $pathInfo = $storage->createPathInfo('test/avatar.png'); $resource = $storage->createResourceFromFile($pathInfo, __DIR__ . '/path/to/uploaded/file.png'); $storage->save($resource); $pathInfo = $pathInfo->withVersion(time()); $entity = new File($storage->createFileInfo($pathInfo)); $em->persist($entity); $em->flush(); # /data/files/test/avatar.png?_v=1611837352 echo (string) $entity->getSource();
与 Latte 一起使用
extensions: 68publishers.file_storage.latte: SixtyEightPublishers\FileStorage\Bridge\Nette\DI\FileStorageLatteExtension
{varType SixtyEightPublishers\FileStorage\FileInfoInterface $fileInfo} {* method FileInfo::__toString() calls ::link() internally so both lines are the same: *} <a href="{$fileInfo->link()}" download>Download a file</a> <a href="{$fileInfo}" download>Download a file</a> {* Create FileInfo from string *} <a href="{file_info('test/invoice.pdf')}" download>Download a file</a>
Symfony 控制台命令
extensions: 68publishers.file_storage.console: SixtyEightPublishers\FileStorage\Bridge\Nette\DI\FileStorageConsoleExtension
清理存储命令
$ bin/console file-storage:clean [<storage>] [--namespace <value>]
复制存储资产
$ bin/console file-storage:copy-assets [<storage>]
贡献
在打开 pull request 之前,请使用以下命令检查您的更改
$ make init # to pull and start all docker images
$ make cs.check
$ make stan
$ make tests.all