josbeir / cakephp-filesystem
CakePHP 4.0+ 文件系统插件
Requires
- php: ^8.0.2
- cakephp/cakephp: ^4.0
- league/flysystem: ^3.0
Requires (Dev)
- cakephp/cakephp-codesniffer: ^4.0
- phpstan/phpstan: ^0.12
- phpunit/phpunit: ^8.0
This package is not auto-updated.
Last update: 2024-09-23 22:03:12 UTC
README
CakePHP 文件系统插件
CakePHP 文件系统插件,使用 Flysystem 作为后端。
原因
- 在您的应用程序中轻松访问 Flysystem 文件系统
- 上传归一化,接受 $_FILES、Zend\Diactoros\UploadedFile 或本地文件系统上的路径
- 文件由可自定义和可 JSON 序列化的实体表示,多个文件通过自定义 Collection 实例返回。
- 有一个 trait 可用,您可以在应用程序的任何地方使用它
- 上传期间可自定义路径/文件名格式,支持自定义格式化器,附带 Default 和 EntityFormatter。
需求
- CakePHP 4.x
- PHP 7.2
安装
您可以使用 composer 将此插件安装到您的 CakePHP 应用程序中。
安装 composer 包的推荐方法是
composer require josbeir/cakephp-filesystem
配置
应在您的 Configure 实例中提供文件系统配置数组。您可以创建一个 config/filesystems.php 文件,内容如下。请确保在 bootstrap.php 中使用 Configure::load('filesystems', 'default');
加载该文件。
为每个 'filesystem' 定义的配置选项直接传递给 Filesystem.php 类。当使用 FilesystemAwareTrait / FilesystemRegistry 类时,必须设置 default
配置。
<?php return [ 'Filesystem' => [ 'default' => [ 'adapter' => 'League\Flysystem\Local\LocalFilesystemAdapter', // default 'adapterArguments' => [ WWW_ROOT . 'files' ] ], 'other' => [ 'adapter' => 'League\Flysystem\Local\LocalFilesystemAdapter', 'adapterArguments' => [ WWW_ROOT . 'cache' ], 'entityClass' => '\My\Cool\EntityClass', 'formatter' => '\My\Cool\Formatter' ] ] ];
简单的上传示例
可以从任何使用 FilesystemAwareTrait 并调用 MyClass::getFilesystem($configKey)
或 FilesystemRegistry::get()
的位置访问 Filesystem 实例。
在这个例子中,我们使用一个虚构的 'myfs' 文件系统定义,如果您将其留空,则在调用 getFilesystem()
时将使用默认 FS。
通过 POST 提交的上传数据
[ 'tmp_name' => '/tmp/blabla', 'filename' => 'lame filename.png', 'error' => 0, 'size' => 1337, 'type' => 'image/png' ]
示例控制器
<?php namespace App\Controller; use Josbeir\Filesystem\FilesystemAwareTrait; class MyController extends AppController { use FilesystemAwareTrait; public function upload() { $fileEntity = $this->getFilesystem('myfs')->upload($this->request->getData('upload')); debug($fileEntity); } }
结果
上述示例的结果将输出一个文件实体类
object(Josbeir\Filesystem\FileEntity) { 'uuid' => 'a105663a-f1a5-40ab-8716-fac211fb01fd', 'path' => 'articles/now_im_called_bar.png', 'filename' => 'lame filename.png', 'filesize' => (int) 28277, 'mime' => 'image/png', 'hash' => '6b16dafccd78955892d3eae973b49c6c', 'meta' => null, 'created' => object(Cake\I18n\Time) { 'time' => '2018-05-27T15:31:54+00:00', 'timezone' => '+00:00', 'fixedNowTime' => false } }
实体属性
当文件成功上传时返回一个可 JSON 序列化的 FileEntity ArrayObject。属性可以通过 get** 和 set** 以及 has** 访问、检查和操作
$entity->hasUuid('a105663a-f1a5-40ab-8716-fac211fb01fd'); $entity->getUuid() // a105663a-f1a5-40ab-8716-fac211fb01fd $entity->setUuid('a105663a-f1a5-40ab-8716-fac211fb01fd'); ... ...
对实体调用 json_encode
// json_encode($entitiy); { "uuid": "3ae258dd-ab1d-425c-b3b0-450f0c702d64", "path": "dummy.png", "filename": "dummy.png", "size": 59992, "mime": "image\/png", "hash": "3ba92ed92481b4fc68842a2b3dcee525", "created": "2018-06-03T09:27:41+00:00", "meta": null }
重建实体
如果您将文件实体作为 JSON 对象保存在某处,则可以使用 Filemanager::newEntity
重建实体
$entity = $this->getFilesystem()->newEntity([ 'uuid' => 'a105663a-f1a5-40ab-8716-fac211fb01fd', 'path' => 'articles/now_im_called_bar.png', 'filename' => 'lame filename.png', 'filesize' => 28277, 'mime' => 'image/png', 'hash' => '6b16dafccd78955892d3eae973b49c6c', 'created' => '2018-05-27T15:31:54+00:00', "meta": [ "extra" => "stuf" ] ]);
重建实体的 Collection
$entities = FileEntityCollection::createFromArray($entities [, string $filesystem]);
使用自己的实体
通过实现 FileEntityInterface 类并设置配置中的实体类 FQCN,可以创建自己的实体。
使用 Cake ORM 实体代替内置实体类的示例
如果您想将实体存储在 ORM 中,可以轻松地将实体类与 ORM 替换。唯一的要求是实体实现 FileEntityInterface
类。
return [ 'Filesystem' => [ 'default' => [ 'entityClass' => 'App\Model\Entity\MyFileEntity' ] ]
然后确保您的 ORM 实体实现 FileEntityInterface 并其所需的方法 'getPath'
namespace App\Model\Entity; use Cake\ORM\Entity; use Josbeir\Filesystem\FileEntityInterface; class MyFileEntity extends Entity implements FileEntityInterface { public function getPath() : string { return $this->path; } public function setPath(string $path) : FileEntityInterface { $this->set('path', $path); return $this; } }
现在,在上传和使用文件时,您可以与 ORM 实体一起工作。
格式化器
在上传过程中,使用格式化器来构建路径和文件名。例如,如果您使用EntityFormatter,则可以使用实体中可用的变量来构建文件名。
$entity = $this->Posts->get(1); $fileEntity = $this->getFilesystem()->upload(TMP . 'myfile.png', [ 'formatter' => 'Entity', // formatter to use 'data' => $entity // data to pass to the formatter ]);
默认的EntityFormatter模式是{entity-source}/{file-name}.{file-ext}
,结果为posts/myfile.png
设置格式化器
格式化器是用于在上传过程中命名和清理文件路径的简单类,此插件目前包含两个格式化器。
- DefaultFormatter,这仅返回'清理后的'文件名
- EntityFormatter,扩展默认格式化器,期望使用EntityInterface作为数据,并用于根据实体数据格式化文件名。
$entity = $this->Posts->get(1); $this->getFilesystem() ->upload(TMP . 'myfile.png', [ 'formatter' => 'Entity', 'data' => $entity, 'pattern' => '{entity-source}/{date-y}-{date-m}-{date-d}-{file-name}-{custom}.{file-ext}', 'replacements' => [ 'custom' => 'key' ] // extra replacement patterns ]);
结果应类似于posts/2018-05-26-myfile-key.png
。
创建自定义格式化器类
创建自己的格式化器类相对简单。该类应实现FormatterInterface
。有关更多信息,请检查DefaultFormatter
或EntityFormatter
类。
示例自定义格式化器
<?php namespace \Path\To\Formatters use Josbeir\Filesystem\DefaultFormatter; class MyFormatter extends DefaultFormatter { // Extra settings? protected $_defaultConfig = [ 'mysetting1' => 'hello' 'mysetting2' => 'world' ]; public function getPath() : string { $setting = $this->getConfig('mysetting1'); $setting2 = $this->getConfig('mysetting2'); return $setting . DS . $setting2 . DS . $this->getBaseName(); } }
在您的应用程序中使用自定义格式化器类
格式化器的FQCN可以在文件系统配置中设置或每次调用setFormatter时设置。
$file = $this->getFilesystem() ->setFormatter('\Path\To\Formatters\MyFormatter') ->upload($file, [ 'mysetting2' => 'cool', ]); debug($file->getPath()) // hello/cool/myfile.png
方法
Filesystem类本身实现了一些关于Flysystem文件系统类的便利方法。
其他方法被代理。如果您希望直接使用Flysystem实例,请使用getDisk()。
// Upload a file // Will fire Filesystem.beforeUpload and Filesystem.afterUpload $this->getFilesystem()->upload($data, $config); // Upload multiple files and returns a FileEntityCollection // Will fire Filesystem.beforeUpload and Filesystem.afterUpload (after each file upload) $this->getFilesystem()->uploadMany($files, $config); // Copy an entity // Will fire Filesystem.beforeCopy and Filesystem.afterCopy $this->getFilesystem()->copy($entity, $config); // Rename an entity // Will fire Filesystem.beforeRename and Filesystem.afterRename $this->getFilesystem()->rename($entity, $config); // Delete an entity from the FS // Will fire Filesystem.beforeDelete and Filesystem.afterDelete $this->getFilesystem()->delete($entity); // Check if a file entity exists on the FS $this->getFilesystem()->exists($entity); // Get Flysystem FS instance $this->getFilesystem()->getDisk(); // Get Flysystem adatapter $this->getFilesystem()->getAdapter(); // Set the formatter class name to be used $this->getFilesystem()->setFormatter($name); // Return a new formatter instance $this->getFilesystem()->newFormatter($filename, $config); // Reset formatter and adapter to default configuration $this->getFilesystem()->reset();
事件
在对文件实体执行操作时将分发事件。目前实现了以下事件
附加功能
更改实体中使用的哈希算法
可以使用文件系统实例配置中的'normalizer'参数将选项传递给FileSourceNormalizer。
<?php return [ 'Filesystem' => [ 'default' => [ 'adapter' => 'League\Flysystem\Local\LocalFilesystemAdapter', 'adapterArguments' => [ WWW_ROOT . 'assets' . DS . 'local' ], 'normalizer' => [ 'hashingAlgo' => 'sha1' ] ] ] ]
访问 Flysytem 对象
因为此插件在核心使用flysystem,所以可以轻松与其他flysystem兼容的代码集成。可以直接使用Filesystem::getDisk()
访问flysystem。
例如,我们可以使用Admad的glide插件,并使用配置的文件系统作为源和缓存。
首先设置默认和缓存配置
<?php return [ 'Filesystem' => [ 'default' => [ 'adapter' => 'League\Flysystem\Local\LocalFilesystemAdapter', 'adapterArguments' => [ WWW_ROOT . 'assets' . DS . 'local' ], 'entityClass' => 'App\Model\Entity\FilesystemFile' ], 'cache' => [ 'adapter' => 'League\Flysystem\Local\LocalFilesystemAdapter', 'adapterArguments' => [ WWW_ROOT . 'assets' . DS . 'cached' ], ] ] ];
然后使用上面提到的配置文件系统设置Glide中间件
use FilesystemAwareTrait; .. .. $routes->registerMiddleware('glide', new GlideMiddleware([ 'server' => [ 'source' => $this->getFilesystem()->getDisk(), 'cache' => $this->getFilesystem('cache')->getDisk() ] ])); $routes->scope('/images', [ 'cache' => false ], function ($routes) { $routes->applyMiddleware('glide'); $routes->connect('/*'); });
贡献
在提交PR之前,请确保