bnbwebexpertise/laravel-attachments

将文件附加到您的模型中,可以通过键、组名或使用 Eloquent 关系检索。

1.0.25 2023-11-16 08:15 UTC

README

此包允许您快速将文件附加到模型中,可以通过键、组名或使用 Eloquent 关系检索。

也可以安装在 Laravel 5.4 上,见下文

安装

您可以通过 composer 安装此包。Laravel 5.5+ 会自动发现服务提供者。

composer require bnbwebexpertise/laravel-attachments

Laravel 5.4 及以下版本安装

为了支持 5.4 版本,请安装 0.0.16 版本

composer require bnbwebexpertise/laravel-attachments:0.0.16

然后,将服务提供者添加到您的配置文件中

'providers' => [
        // ...

        Bnb\Laravel\Attachments\AttachmentsServiceProvider::class,

        // ...
],

配置

您可以通过发布配置文件来自定义此包的行为

php artisan vendor:publish --provider='Bnb\Laravel\Attachments\AttachmentsServiceProvider'

将附件添加到模型类中

HasAttachment 特性添加到您的模型类中

<?php

namespace App;

use Bnb\Laravel\Attachments\HasAttachment;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable, HasAttachment;

    // ...
}

然后将其用于绑定一个文件到实例

$user = App\User::create([
    'name' => 'name',
    'email' => 'email@foo.bar',
    'password' => 'password',
]);

// Bind a local file
$attachment = $user->attach('local/path/to/file.txt');

// Bind an uploaded file
$attachment = $user->attach(\Request::file('uploaded_file'));

// Bind an uploaded file with options
$attachment = $user->attach(\Request::file('uploaded_file'), [
    'disk' => 's3',
    'title' => \Request::input('attachment_title'),
    'description' => \Request::input('attachment_description'),
    'key' => \Request::input('attachment_key'),
]);

检索模型的附件

$user = App\User::first();

$allAttachments = $user->attachments()->get();

$attachmentByKey = $user->attachment('myKey');

// Attachment public URL
$publicUrl = $attachmentByKey->url;

重新分组模型的附件

使用 group 属性可以对附件进行分组。由 HasAttachment 特性提供的 attachmentsGroup 方法返回所有具有给定 group 值的附件。

$user = App\User::first();

$user->attach($somefile, ['
    'group' => 'album',
']);

$user->attach($otherfile, ['
    'group' => 'album',
']);

$attachmentsByGroup = $user->attachmentsGroup('album');

删除附件

在附件模型实例上调用 delete() 方法将删除数据库行和文件。可以通过在配置中将 behaviors.cascade_delete 设置为 false 来禁用文件的删除。

请注意,在 query() 语句上调用 delete() 不会级联到文件系统,因为它不会调用 Attachment 模型类的 delete() 方法。

$user = App\User::first();
$attachmentByKey = $user->attachment('myKey');
$attachmentByKey->delete(); // Will also delete the file on the storage by default

钩子文件输出

Bnb\Laravel\Attachments\Attachment 模型类提供了一个 outputting 事件,您可以观察它。

在应用程序服务提供者中,您可以编写如下代码

<?php
use Bnb\Laravel\Attachments\Attachment;

class AppServiceProvider extends ServiceProvider
{
    // ...

    public function boot() {

        // ...

        Attachment::outputting(function ($attachment) {
            /** @var Attachment $attachment */

            // Get the related model
            $model = $attachment->model;

            if (empty($model)) {
                // Deny output for attachments not linked to a model

                return false;
            }

            if ($model instanceof \App\User) {
                // Check if current user is granted and owner

                $user = \Auth::user();

                return $user && $user->can('download-file') && $user->id == $model->id;
            }
        });

        // ...
    }


    // ...
}

Dropzone

上传

此包提供了通过 attachments.dropzone 路由别名对 Dropzone.js 或等效的端点进行服务器端点的支持。

它以 JSON 响应返回附件的 uuid 以及其他字段。该值可以稍后发送回服务器,以便将其绑定到模型实例(延迟保存)。

表单

<form action="{{ route('attachments.dropzone')  }}" class="dropzone" id="my-dropzone">
    {{ csrf_field() }}
</form>

响应

{
  "title": "b39ffd84524b",
  "filename": "readme.md",
  "filesize": 2906,
  "filetype": "text\/html",
  "uuid": "f5a8eec2-d860-4e53-8451-b39ffd84524b",
  "key": "58ac52e90db938.72105394",
  "url": "http:\/\/laravel.dev:8888\/attachments\/f5a8eec2-d860-4e53-8451-b39ffd84524b\/readme.md"
}

稍后发送

<form action="/upload" method="post">
    {{ csrf_field() }}
    <input type="hidden" name="attachment_id" id="attachment_id">
    <button type="submit">Save</button>
</form>

<!-- Where attachment_id is populated on success -->

<script>
    Dropzone.options.myDropzone = {
        init: function () {
            this.on("success", function (file, response) {
                document.getElementById('attachment_id').value = response.uuid;
            });
        }
    };
</script>

稍后绑定

<?php

Route::post('/upload', function () {
    $model = App\User::first();

    Bnb\Laravel\Attachments\Attachment::attach(Request::input('attachment_id'), $model);

    return redirect('/dropzone');
});

删除

可以通过 HTTP DELETE 调用 attachments.dropzone.delete 路由。必须提供附件 ID 作为参数。

此路由提供的删除操作 仅适用于挂起的附件(未绑定到模型)。

为了避免删除其他用户的文件,当前 CSRF 令牌在通过 dropzone 端点上传时被保存,并且在调用 dropzone 删除端点时必须相同。此行为可以通过配置或环境键来禁用(见 config/attachments.php)。

使用示例

<script>
var MyDropzone = {
    url: "{{ route('attachments.dropzone.delete', ['id' => ':id']) }}"
    // ...
    deletedfile: function (file) {
        axios.delete(this.url.replace(/:id/, file.id)).then(function () {
            //...
        });
    }
    //...
}
</script>

事件

dropzone 端点控制器会触发两个事件

  • attachments.dropzone.uploading,参数为 $request : Request
  • attachments.dropzone.deleting,参数为 $request : Request$file : Attachement

如果任何一个监听器返回 false,则操作将被终止。

public function boot()
{
    Event::listen('attachments.dropzone.uploading', function ($request) {
        return $this->isAllowedToUploadFile($request);
    });

    Event::listen('attachments.dropzone.deleting', function ($request, $file) {
        return $this->canDeletePendingFile($request, $file);
    });
}

临时 URL

可以使用Attachment模型中的getTemporaryUrl方法生成一个唯一的临时URL来下载附件,主要用于分享。
getTemporaryUrl方法有一个参数:一个Carbon日期,在此日期之后链接将不再有效。

默认生成的URL形式为:http://example.com/attachments/shared/<一个非常长的字符串>。共享路径可以在配置文件中的shared_pattern键下进行修改。

清理命令

提供了一个命令来清理未绑定到模型的附件(当model_typemodel_idnull时)。

php artisan attachment:cleanup

可以使用-s(或--since=[timeInMinutes])选项来设置另一个时间限制(以分钟为单位):只有超过指定年龄的无关联文件将被删除。此值默认设置为1440

迁移命令

要将所有附件从源磁盘迁移到另一个磁盘

php artisan attachments:migrate public s3

如果成功保存到目标磁盘,则从源磁盘中删除文件。

自定义

为模型设置自定义数据库连接名称

您可以通过以下方式自定义数据库连接名称:

  • 添加一个.env变量用于ATTACHMENTS_DATABASE_CONNECTION(推荐)或者
  • 更改配置选项attachments.database.connectionconfig/attachments.php中。

扩展附件模型列

配置定义了在attachment.attributes键中的可填充附件属性列表。

这允许您创建迁移来在附件表中添加新列,并在config/attachments.php的发布配置中声明它们。

自定义附件存储目录前缀

您可以通过以下方式轻松自定义新附件存储的文件夹/前缀:

  • 添加一个.env变量用于ATTACHMENTS_STORAGE_DIRECTORY_PREFIX(推荐)或者
  • 更改配置选项attachments.storage_directory.prefixconfig/attachments.php中。

默认值为attachments,任何尾随的/将被自动裁剪。

自定义附件存储文件路径

如果您不希望使用默认的存储文件路径生成,您可以提供filepath选项(相对于存储磁盘的根目录)。它必须包含目录和文件名。确保提供的文件路径不与其他文件冲突。

$model->attach('/foo/bar/pdf.pdf', ['filepath' => 'foo/bar/test.pdf']);

此选项不适用于通过集成的DropZone控制器上传的附件。仅适用于显式附件。

扩展附件模型类

这有助于向附件模型添加一些关系。

创建一个扩展Bnb\Laravel\Attachments\Attachment的自定义模型

<?php
namespace App;

class MyAttachment extends Bnb\Laravel\Attachments\Attachment
{
    // ...
    public function someCustomRelation() {
        // ...
    }
    // ...
}

要配置您自己的模型类,您可以使用以下可能性之一:

  • 发布配置并更新attachment_model
  • 设置环境变量ATTACHMENTS_MODEL
  • 在服务提供者中将您的模型绑定到Bnb\Laravel\Attachments\Contracts\AttachmentContract接口

示例

<?php
return [
    // ...
    'attachment_model' => \App\MyAttachment::class,
    // ..
];
# ...
ATTACHMENTS_MODEL=\App\MyAttachment
# ...
<?php
// ...

class AppServiceProvider extends ServiceProvider {
    // ...
    public function register()
    {
        // ...
        $this->app->bind(
            \Bnb\Laravel\Attachments\Contracts\AttachmentContract::class,
            \App\MyAttachment::class
        );
        // ...
    }
    // ...
}