atk4 / filestore
ATK UI 表单上传字段与 PHP Flysystem 的集成
Requires
- php: >=7.4 <8.4
- atk4/ui: ~5.0.0
- league/flysystem: ^2.0
Requires (Dev)
- ergebnis/composer-normalize: ^2.13
- friendsofphp/php-cs-fixer: ^3.0
- johnkary/phpunit-speedtrap: ^3.3
- phpstan/extension-installer: ^1.1
- phpstan/phpstan: ^1.0
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-strict-rules: ^1.3
- phpunit/phpunit: ^9.5.5
README
从 ATK UI 1.4 版本开始,它增加了对文件和图像上传的支持。在其原始形式中,开发者负责在上传文件后对其进行处理。在大多数情况下,开发者可能希望将文件存储在本地或远程文件系统中,但需要自己执行此操作。
Filestore 是一个用于 ATK 数据和 ATK UI 的插件,它提供了与 Flysystem 无缝集成。
简介
使用 Filestore 将文件附加到数据库记录非常简单。以下示例可以在几行代码内实现并添加到您的 PHP 应用程序中。
由于 ATK 表单使用 AJAX 提交,文件必须在选择后立即发送到服务器。文件立即放置在 flysystem 中(在演示中我使用的是本地存储),并在数据库中创建一个包含有关文件的全部信息的记录,包括是否为图像以及如果是图像,则包括尺寸。
生成两个随机标识符 - 一个用于实际的文件名(以确保您不会覆盖现有文件),另一个(令牌)将用于引用文件。实际上您根本看不到令牌,但它用于保持安全。
您可以直接在 CRUD 中上传文件,并且可以拥有多个文件字段。
在您的主要表中,您只需要一个 varchar
字段来存储文件令牌。如果您使用 SQL,则可以访问额外的字段,如原始文件名等。
这对于您需要在自定义模板中包含所有这些字段的情况非常有价值。
安装和代码
要安装,请运行 composer require atk4\filestore
并需要创建 filestore_file
表。在模型定义中,您只需声明一个新的字段。
$this->addField('file', [\Atk4\Filestore\Field\FileField::class, 'flysystem' => $this->getApp()->filesystem]);
这基本上就处理了所有事情!有关完整示例,请参阅文件 demos/basic.php
。
功能
目前实现了以下功能
- 美观的文件上传界面和与 ATK UI 表单的完整集成。上传跟踪带有进度条。
- 保持文件整洁,删除记录也会删除相关联的文件。上传但未链接的文件将保留在“草案”状态,您可以定期清理它们。
- 通过与 flysystem 集成,支持任何存储。
- 非常灵活,可以使用不同的表,不同地映射字段,使用多个位置,添加自定义操作等等。
- 文件可以基于 "user_id" 进行范围限制,以提供进一步的安全性(即使用户知道令牌,用户也无法访问其他用户的图像)。
路线图
对于即将推出的版本,我们有以下想法。如果您想帮助实现以下任何功能(或赞助),请联系 @romaninsh (https://gitter.im/atk4/atk4)。
- 指定要接受的扩展名和/或文件类型。
- 轻松下载之前上传的文件。
- 添加自动缩略图创建。与原始图像一起删除缩略图。
- 指定上传、链接、取消链接和删除的自定义操作。
- 显示文件类型的图标或图像的预览。
- 添加交互式裁剪。
- 添加验证文件的方法。
- 添加拖放上传。
- 为大型拖放目标添加新视图或使用任意视图(无需表单上传)。
- 添加“文件管理”的UI。
- 支持从原始图片重新裁剪缩略图。
- 集成NoSQL持久化支持。
- 在存储前加密文件,在加载时解密。
- 添加将文件“哈希”到子目录的选项。
旧README
事件,因此文件上传将在文件被选中时立即发生。但是,有一些条件,当文件已上传/删除但表单未提交时。
成功完成后,PHP端回调执行以生成ID。 Filestore提供此回调并执行以下操作
- 收集有关文件的信息 - 原始文件名、大小、MIME类型等。
- 在“文件”模型中存储信息,生成ID。
- 使用随机名称将文件移动到Flysystem中,并在“文件”模型中记录。
- 返回文件的ID,然后将其传递回表单提交处理程序。
示例
如果您有一个如Friend
的模型,并且希望上传朋友的照片,Filestore提供了一种很好的集成方式
// in Friend::init(); $this->addField('photo_file_token', [\Atk4\Filestore\Field\FileField::class]);
此字段将自动出现在表单中作为上传字段,但在数据库中将存储来自“文件”模型的“token”。您甚至可以定义多个这样的字段。
默认情况下,将使用本地文件存储,但您可以通过将配置传递到您的字段来配置不同的位置
$this->addField('photo_file_token', [ \Atk4\Filestore\Field\FileField::class, // specify if you want to only accept certain types of files or extensions. 'onlyTypes' => ['image/*', 'application/x-pdf'], 'onlyExtensions' => ['img', 'png', 'pdf'], // safer to specify both // where to store 'flysystem' => $flysystem, // you can also define callback if you wish to do something more with the file 'onUpload' => function ($file) { // do something with file }, // this is called when form with the file is submitted 'onAttach' => function ($file) { // $file is a model object }, // when user detaches file from the related entity 'onDetach' => function ($file) { // $file is a model object }, ])
如果您打开已附加文件的Friend
表单,您将能够删除文件。但是,“删除”文件不一定意味着它们将被解除关联,用户仍然可以点击“取消”。然而,当表单保存时,如果文件被删除,它也将从存储和File
表中删除。
图像
Filestore还实现了\Atk4\Filestore\Field\Image
类,该类通过扩展File自动裁剪并存储图像的各种缩略图,从而提供额外功能。
$this->addField('picture_id', [ \Atk4\Filestore\Field\Image::class, // no need to specify types, will only accept valid images // where to store 'flysystem' => $flysystem, // you can still define this if you wish to pre-process your file, e.g. add watermark 'onUpload' => function ($file) { // do something with file }, // cropping table 'crop' => [ 'medium' => [200, 300], // width, height 'small' => [50, 50], ], ])
裁剪将保持原始图像的纵横比,但将确保图像被填充。将使用“imagick”或“gd”进行操作。参数定义如下
0 => 200
,宽度1 => height
,高度'type' => 'jpeg'
可选。默认为'png'
为了存储缩略图,Filestore将在File
表中创建额外的文件。
文件模型
Filestore附带一个自定义模型Atk4\Filestore\Model\File
,该模型设计用于存储文件元信息。对于每个上传的文件,它存储以下内容
- file_token - 随机生成,用于在表单中传递回提交处理程序
- location - (用于在Flysystem中标识文件。随机生成)
- storage - (有关所使用存储的简短信息)
- source_file_id (指定原始文件的ID。用于缩略图或其他生成文件)
- status (定义文件当前的位置)
定义了几个“元”字段,用于描述文件内容
- meta_filename
- meta_extension
- meta_md5
- meta_mime_type
- meta_size
- meta_is_image
- meta_image_width
- meta_image_height
方法
$file->createFromPath('path/to/file.txt', 'my_file.txt');
创建一个File
实体,将数据保存到flysystem
并保存实体。
$stream = $file->getStream();
返回文件内容的流。您可以通过调用$stream->getContents()
来获取文件内容作为字符串。
路线图
一些可能的功能
- 添加“临时”位置以存储文件
- 在通过模型加载随机文件时允许初始化Flysystem详细信息