68publishers/file-storage

基于 Flysystem 的文件管理,并集成到 Nette 框架中。

v1.1.3 2024-08-06 02:38 UTC

This package is auto-updated.

Last update: 2024-09-06 02:49:59 UTC


README

📁 基于 Flysystem 的文件管理,并集成到 Nette 框架

Checks Coverage Status Total Downloads Latest Version PHP Version

安装

使用 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 容器将包含自动注入的 FileStorageProviderInterfaceFileStorageInterface(默认存储)服务。

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