tecdiary/laravel-attachments

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

安装次数: 1,427

依赖者: 0

建议者: 0

安全: 0

星标: 0

关注者: 0

分支: 28

类型:软件包

1.1.1 2022-11-24 08:20 UTC

README

此仓库是 B&N Web Expertisebnbwebexpertise/laravel-attachments 的分支。

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

安装

您可以通过 composer 安装此软件包。

composer require tecdiary/laravel-attachments

配置

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

php artisan vendor:publish --provider='Tecdiary\Laravel\Attachments\AttachmentsServiceProvider' --tag="config"

迁移

此软件包将加载迁移,但如果您不想,可以通过软件包调用 AttachmentsServiceProvider::ignoreMigrations() 来发布迁移并停止加载迁移。

php artisan vendor:publish --provider="Tecdiary\Laravel\Attachments\AttachmentsServiceProvider" --tag="migrations"

php artisan migrate

在 AppServiceProvider 的 register 方法中添加以下行

\Tecdiary\Laravel\Attachments\AttachmentsServiceProvider::ignoreMigrations();

将附件添加到模型类中

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

<?php

namespace App;

use Tecdiary\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

钩子文件输出

Tecdiary\Laravel\Attachments\Attachment 模型类提供了一个可观察的 outputting 事件。

在应用程序服务提供程序中,您可以编写例如

<?php
use Tecdiary\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();

    Tecdiary\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

可以通过附件模型的 getTemporaryUrl 方法生成一个唯一的临时 URL,用于下载附件,主要用于分享。该方法有一个参数:一个 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

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

自定义

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

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

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

扩展附件模型列

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

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

自定义附件存储目录前缀

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

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

默认值为 attachments,任何尾随的 / 将自动删除。

自定义附件存储文件路径

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

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

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

扩展附件模型类

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

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

<?php
namespace App;

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

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

  • 发布配置并更新 attachment_model
  • 设置 ATTACHMENTS_MODEL 环境值
  • 在服务提供者中将您的模型绑定到 Tecdiary\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(
            \Tecdiary\Laravel\Attachments\Contracts\AttachmentContract::class,
            \App\MyAttachment::class
        );
        // ...
    }
    // ...
}