itstructure / laravel-media-file-uploader
用于 Laravel 框架的媒体文件上传器
Requires
- php: >=7.2.5
- itstructure/laravel-grid-view: ^1.1.3
- laravel/framework: ^6.0|^7.0|^8.0|^9.0|^10.0|^11.0
README
1 简介
此包用于将不同的媒体文件上传到本地或远程的 Amazon S3 存储。
2 要求
- laravel 6+ | 7+ | 8+ | 9+ | 10+ | 11+
- Bootstrap 4 用于样式
- JQuery
- php >= 7.2.5
- composer
- 以下 PHP 扩展之一:GD|Imagick|Gmagick
3 安装
3.1 安装包
从远程 Packagist 仓库的通用部分
运行 composer 命令
composer require itstructure/laravel-media-file-uploader "^1.0.3"
如果您正在从本地服务器目录测试此包
在应用程序 composer.json
文件中设置仓库,如下例所示
"repositories": [ { "type": "path", "url": "../laravel-media-file-uploader", "options": { "symlink": true } } ],
这里,
../laravel-media-file-uploader - 目录路径,与应用程序处于同一目录级别,并包含 MFU 包。
然后运行命令
composer require itstructure/laravel-media-file-uploader:dev-main --prefer-source
3.3 发布文件 - 必需部分
-
要发布配置,运行命令
php artisan uploader:publish --only=config
它将配置文件存储到
config
文件夹。否则,您可以使用
--force
参数重写已发布的文件。 -
要发布迁移,运行命令
php artisan uploader:publish --only=migrations
它将迁移文件存储到
database/migrations
文件夹。否则,您可以使用
--force
参数重写已发布的文件。 -
要发布资产(js 和 css),运行命令
php artisan uploader:publish --only=assets
它将 js 和 css 文件存储到
public/vendor/uploader
文件夹。否则,您可以使用
--force
参数重写已发布的文件。
3.4 发布文件 - 自定义部分
-
要发布视图,运行命令
php artisan uploader:publish --only=views
它将视图文件存储到
resources/views/vendor/uploader
文件夹。否则,您可以使用
--force
参数重写已发布的文件。 -
要发布翻译,运行命令
php artisan uploader:publish --only=lang
它将翻译文件存储到
resources/lang/vendor/uploader
文件夹。否则,您可以使用
--force
参数重写已发布的文件。
3.5 发布文件 - 如有需要,发布所有部分
-
要发布所有部分,请运行不带
only
参数的命令php artisan uploader:publish
否则,您可以使用
--force
参数重写已发布的文件。
3.6 运行迁移
- 运行命令
php artisan migrate
4 配置
4.1 设置默认文件系统磁盘
在配置文件 filesystems.php
中设置以下自定义设置(设置您希望设置的默认磁盘)并创建所需的基上传文件夹
'default' => env('FILESYSTEM_DISK', 'local'), 'disks' => [ 'local' => [ 'driver' => 'local', 'root' => storage_path('app/uploads'), 'throw' => false, 'url' => env('APP_URL') . '/storage/', ], 's3' => [ 'driver' => 's3', 'key' => env('AWS_ACCESS_KEY_ID'), 'secret' => env('AWS_SECRET_ACCESS_KEY'), 'region' => env('AWS_DEFAULT_REGION'), 'bucket' => env('AWS_BUCKET'), 'url' => env('AWS_URL'), 'endpoint' => env('AWS_ENDPOINT'), 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), 'throw' => false, 'visibility' => 'public', ], ], 'links' => [ public_path('storage') => storage_path('app/uploads'), ],
运行命令以创建符号链接
php artisan storage:link
4.2 设置资产
注意!此选项仅在以下情况下需要
-
如果您在应用程序 html 表单中使用 File setter(请参阅 5.3 深入研究 / 5.3.3 使用 FileSetter 点)。
-
如果您使用 相册编辑器(请参阅 5.1 路由部分)。
请确保您在应用程序中使用 Bootstrap 4 进行样式和 JQuery。
4.2.1 自定义主体布局情况
因此,在您的应用程序布局的 head
标签之间设置以下 css 资产
<link rel="stylesheet" href="{{ asset('vendor/uploader/css/modal.css') }}"> <link rel="stylesheet" href="{{ asset('vendor/uploader/css/file-area.css') }}">
在您的应用程序布局的 body
标签的末尾设置以下 js 资产
<script src="{{ asset('vendor/uploader/js/jquery.min.js') }}"></script> <script src="{{ asset('vendor/uploader/js/file-setter.js') }}"></script>
注意:vendor/uploader/js/jquery.min.js
仅当您的应用程序中缺少 JQuery 时才需要。
4.2.2 如果您在项目中使用 AdminLTE 包
'plugins' => [ 'Uploader' => [ 'active' => true, 'files' => [ [ 'type' => 'css', 'asset' => true, 'location' => '/vendor/uploader/css/modal.css', ], [ 'type' => 'css', 'asset' => true, 'location' => '/vendor/uploader/css/file-area.css', ], [ 'type' => 'js', 'asset' => true, 'location' => '/vendor/uploader/js/file-setter.js', ], ], ], ]
注意:不建议在 AdminLTE 配置文件中使用 asset()
,因为这可能在您稍后运行例如 composer install
时导致与 UrlGenerator.php 相关的错误。
4.3 修改 uploader.php
配置文件。
此文件是 直观的。
但是在这个阶段,请注意下一个重要的选项
-
路由中间件。默认情况下为空数组,您可以设置如下
'routing' => [ 'middlewares' => ['auth'], ],
这些中间件将在
routes/uploader.php
中应用。 -
相册布局(如果使用相册编辑器则必须设置)。默认情况下为空字符串,您可以设置如下
'albums' => [ 'layout' => 'adminlte::page', // In case if you use AdminLTE. Or you can set your special layout. ],
5 使用方法
5.1 路由部分
已经集成了基础 MFU 路由来管理 文件 和 相册。请参阅 routes/uploader.php
包文件。
以下路由默认可用
-
上传部分
对于 GET 请求方法
http://example-domain.com/uploader/file/download/{id}
(名称: uploader_file_download)
对于 POST 请求方法
-
http://example-domain.com/uploader/file/upload
(名称: uploader_file_upload)- 必需的请求字段是 file。
- 可选/必需的请求元数据字段: [data]alt, [data]title, [data]description, [data]owner_id, [data]owner_name, [data]owner_attribute, [data]needed_file_type, [data]sub_dir。
-
http://example-domain.com/uploader/file/update
(名称: uploader_file_update)- 必需的请求字段是 id。
- 可选的请求字段是 file。
- 可选/必需的请求元数据字段: [data]alt, [data]title, [data]description, [data]needed_file_type, [data]sub_dir。
-
http://example-domain.com/uploader/file/delete
(名称: uploader_file_delete)- 必需的请求字段是 id。
-
http://example-domain.com/uploader/file/preview
(名称: uploader_file_preview)- 必需的请求字段是 id。
- 可选的请求字段是 location。有关 preview 选项的更多信息,请参阅配置文件
uploader.php
(其中包含针对具体文件类型及其预览的一些 html 属性)。如果没有设置,返回的预览将具有与Previewer::LOCATION_FILE_INFO
相符的 html 属性。如果它是一个图像,Previewer
将返回一个带有大小并根据配置中的 thumbAlias 选项的图像。如果没有设置 thumbAlias 或没有这样的位置,Previewer
将返回一个根据SaveProcessor::THUMB_ALIAS_SMALL
的大小调整的图像。
注意
- 如果上传的文件是 图像,则会根据 thumbSizes 配置选项中的设置创建额外的缩略图。
- 请求元数据字段的必要性/可选性在配置文件
uploader.php
中的 metaDataValidationRules 选项中设置。 - 如果 checkExtensionByFileType 选项为 true,则自动要求 [data]needed_file_type。
-
管理部分
对于 GET 请求方法
http://example-domain.com/uploader/managers/file-list
(名称: uploader_file_list_manager)http://example-domain.com/uploader/managers/file-upload
(名称: uploader_file_upload_manager)http://example-domain.com/uploader/managers/file-edit/{id}
(名称: uploader_file_edit_manager)
对于 POST 请求方法
http://example-domain.com/uploader/managers/file-list/delete
(名称: uploader_file_list_delete)- 必需的请求字段是 items - 它是一个文件 ID 的数组。
-
相册编辑器部分
-
图片相册
对于 GET 请求方法
http://example-domain.com/uploader/albums/image/list
(名称: uploader_image_album_list)http://example-domain.com/uploader/albums/image/create
(名称: uploader_image_album_create)http://example-domain.com/uploader/albums/image/edit/{id}
(名称: uploader_image_album_edit)http://example-domain.com/uploader/albums/image/view/{id}
(名称: uploader_image_album_view)
对于 POST 请求方法
http://example-domain.com/uploader/albums/image/store
(名称: uploader_image_album_store)http://example-domain.com/uploader/albums/image/update/{id}
(名称: uploader_image_album_update)http://example-domain.com/uploader/albums/image/delete
(名称: uploader_image_album_delete)
-
音频相册
对于 GET 请求方法
http://example-domain.com/uploader/albums/audio/list
(名称: uploader_audio_album_list)http://example-domain.com/uploader/albums/audio/create
(名称: uploader_audio_album_create)http://example-domain.com/uploader/albums/audio/edit/{id}
(名称: uploader_audio_album_edit)http://example-domain.com/uploader/albums/audio/view/{id}
(名称:uploader_audio_album_view)
对于 POST 请求方法
http://example-domain.com/uploader/albums/audio/store
(名称:uploader_audio_album_store)http://example-domain.com/uploader/albums/audio/update/{id}
(名称:uploader_audio_album_update)http://example-domain.com/uploader/albums/audio/delete
(名称:uploader_audio_album_delete)
-
视频专辑
对于 GET 请求方法
http://example-domain.com/uploader/albums/video/list
(名称:uploader_video_album_list)http://example-domain.com/uploader/albums/video/create
(名称:uploader_video_album_create)http://example-domain.com/uploader/albums/video/edit/{id}
(名称:uploader_video_album_edit)http://example-domain.com/uploader/albums/video/view/{id}
(名称:uploader_video_album_view)
对于 POST 请求方法
http://example-domain.com/uploader/albums/video/store
(名称:uploader_video_album_store)http://example-domain.com/uploader/albums/video/update/{id}
(名称:uploader_video_album_update)http://example-domain.com/uploader/albums/video/delete
(名称:uploader_video_album_delete)
-
应用程序专辑
对于 GET 请求方法
http://example-domain.com/uploader/albums/application/list
(名称:uploader_application_album_list)http://example-domain.com/uploader/albums/application/create
(名称:uploader_application_album_create)http://example-domain.com/uploader/albums/application/edit/{id}
(名称:uploader_application_album_edit)http://example-domain.com/uploader/albums/application/view/{id}
(名称:uploader_application_album_view)
对于 POST 请求方法
http://example-domain.com/uploader/albums/application/store
(名称:uploader_application_album_store)http://example-domain.com/uploader/albums/application/update/{id}
(名称:uploader_application_album_update)http://example-domain.com/uploader/albums/application/delete
(名称:uploader_application_album_delete)
-
文档专辑
对于 GET 请求方法
http://example-domain.com/uploader/albums/word/list
(名称:uploader_word_album_list)http://example-domain.com/uploader/albums/word/create
(名称:uploader_word_album_create)http://example-domain.com/uploader/albums/word/edit/{id}
(名称:uploader_word_album_edit)http://example-domain.com/uploader/albums/word/view/{id}
(名称:uploader_word_album_view)
对于 POST 请求方法
-
http://example-domain.com/uploader/albums/word/store
(名称:uploader_word_album_store) -
http://example-domain.com/uploader/albums/word/update/{id}
(名称:uploader_word_album_update) -
http://example-domain.com/uploader/albums/word/delete
(名称:uploader_word_album_delete).........................................................
……下一专辑……
.........................................................
-
等等... 在 routes/uploader.php
包文件中查看下一专辑的路由,包括 Excel、Visio、PowerPoint、PDF、Text、其他 专辑。它们遵循相似的原则。
专辑编辑器 POST 请求方法的字段对所有专辑都相同
- 存储所需的请求字段:标题、描述。
- 更新所需的请求字段:标题、描述。字段 id 在路由 URL 中。
- 删除所需的请求字段:items - 它是包含专辑 ID 的数组。
5.2 简便快捷的方式
5.2.1 访问文件列表管理器
-
直接访问 uploader_file_list_manager 路由:
http://example-domain.com/uploader/managers/file-list
-
使用 iframe 访问文件列表
<section class="content container-fluid"> <div class="row"> <div class="col-12 mt-1"> <iframe src="{{ route('uploader_file_list_manager') }}" frameborder="0" style="width: 100%; min-height: 800px"></iframe> </div> </div> </section>
5.2.2 访问文件上传管理器
如果在文件列表管理器中点击绿色的 Uploader 按钮,您将转到 uploader_file_upload_manager 路由:http://example-domain.com/uploader/managers/file-upload
。
5.2.3 访问文件编辑管理器
如果在文件列表管理器中点击绿色的编辑按钮,您将转到 uploader_file_edit_manager 路由:http://example-domain.com/uploader/managers/file-edit/{id}
route('uploader_file_edit_manager', ['id' => 1])
5.2.4 访问媒体文件预览
如果您通过 Itstructure\MFU\Models\Mediafile
模型实体获得了媒体文件条目 $mediaFile
<a href="{{ $mediaFile->getOriginalUrl() }}" target="_blank"> {!! \Itstructure\MFU\Facades\Previewer::getPreviewHtml($mediaFile, \Itstructure\MFU\Services\Previewer::LOCATION_FILE_INFO) !!} </a>
您可以使用以下选项之一
\Itstructure\MFU\Services\Previewer::LOCATION_FILE_ITEM
\Itstructure\MFU\Services\Previewer::LOCATION_FILE_INFO
\Itstructure\MFU\Services\Previewer::LOCATION_EXISTING
5.2.5 下载媒体文件
使用路由
route('uploader_file_download', ['id' => 1])
5.2.6 访问专辑编辑器
只需使用上述 5.1 路由部分 中的 专辑编辑器 部分描述的专辑路由。
但请注意!您必须为专辑编辑器设置布局
'albums' => [ 'layout' => 'adminlte::page', ],
值 adminlte::page
用于您使用 AdminLTE 的情况。或者您也可以设置您自己的特殊布局。
图片专辑列表示例看起来像这样
图片专辑编辑页面示例看起来像这样
5.3 深入挖掘
5.3.1 数据库结构
5.3.2 简单地说,上传过程的短架构结构和请求方式
-
调用
UploadController
方法。 -
在控制器方法中调用来自
Itstructure\MFU\Facades\Uploader
门面的静态方法。 -
获取 Uploader 服务实例
Itstructure\MFU\Services\Uploader::getInstance($config)
并在此处调用门面的方法。 -
获取所需处理器的实例,并将配置数据从服务设置到此处
Itstructure\MFU\Processors\UploadProcessor
或Itstructure\MFU\Processors\UpdateProcessor
或Itstructure\MFU\Processors\DeleteProcessor
. -
设置处理参数,然后调用其
run()
方法。
查看核心内部。
5.3.3 使用 FileSetter
FileSetter 在保存某些实体(如页面、目录、产品等)之前,将文件 ID 设置到表单字段并将文件预览设置到特殊容器中时是必需的。
以下是用于 缩略图 的 FileSetter 示例
@php $thumbModel = isset($model) ? $model->getThumbnailModel() : null; @endphp <div id="{{ isset($model) ? 'thumbnail_container_' . $model->id : 'thumbnail_container' }}"> @if(!empty($thumbModel)) <a href="{{ $thumbModel->getOriginalUrl() }}" target="_blank"> {!! \Itstructure\MFU\Facades\Previewer::getPreviewHtml($thumbModel, \Itstructure\MFU\Services\Previewer::LOCATION_FILE_INFO) !!} </a> @endif </div> <div id="{{ isset($model) ? 'thumbnail_title_' . $model->id : 'thumbnail_title' }}"> @if(!empty($thumbModel)) {{ $thumbModel->title }} @endif </div> <div id="{{ isset($model) ? 'thumbnail_description_' . $model->id : 'thumbnail_description' }}"> @if(!empty($thumbModel)) {{ $thumbModel->description }} @endif </div> @php $fileSetterConfig = [ 'attribute' => Itstructure\MFU\Processors\SaveProcessor::FILE_TYPE_THUMB, 'value' => !empty($thumbModel) ? $thumbModel->id : null, 'openButtonName' => trans('uploader::main.set_thumbnail'), 'clearButtonName' => trans('uploader::main.clear'), 'mediafileContainerId' => isset($model) ? 'thumbnail_container_' . $model->id : 'thumbnail_container', 'titleContainerId' => isset($model) ? 'thumbnail_title_' . $model->id : 'thumbnail_title', 'descriptionContainerId' => isset($model) ? 'thumbnail_description_' . $model->id : 'thumbnail_description', //'callbackBeforeInsert' => 'function (e, v) {console.log(e, v);}',//Custom 'neededFileType' => Itstructure\MFU\Processors\SaveProcessor::FILE_TYPE_THUMB, 'subDir' => isset($model) ? $model->getTable() : null ]; $ownerConfig = isset($ownerParams) && is_array($ownerParams) ? array_merge([ 'ownerAttribute' => Itstructure\MFU\Processors\SaveProcessor::FILE_TYPE_THUMB ], $ownerParams) : []; $fileSetterConfig = array_merge($fileSetterConfig, $ownerConfig); @endphp @fileSetter($fileSetterConfig)
从视觉上看,它看起来像这样
如果单击 设置缩略图 按钮,则将打开文件列表管理器,但带有额外的按钮 "V"
此按钮用于选择具体文件,并将其预览插入到 thumbnail_container
中,并将其 ID 插入到由 attribute
选项自动渲染的表单字段中。
查看下一节 5.3.4 以了解如何将所选文件与父所有者关联,例如:页面、产品等...
5.3.4 将媒体文件与父所有者关联
例如,您使用包含 专辑 和 媒体文件 的 Product
eloquent 模型。
在产品保存后,通过 owners_albums
和 owners_mediafiles
数据库关系,可以将专辑和媒体文件与产品关联。
这些关系由 BehaviorMediafile
和 BehaviorAlbum
类自动设置。
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Itstructure\MFU\Interfaces\BeingOwnerInterface; use Itstructure\MFU\Behaviors\Owner\{BehaviorMediafile, BehaviorAlbum}; use Itstructure\MFU\Processors\SaveProcessor; use Itstructure\MFU\Models\Albums\AlbumTyped; use Itstructure\MFU\Traits\{OwnerBehavior, Thumbnailable}; class Product extends Model implements BeingOwnerInterface { use Thumbnailable, OwnerBehavior; protected $table = 'products'; protected $fillable = ['title', 'alias', 'description', 'price', 'category_id']; public function getItsName(): string { return $this->getTable(); } public function getPrimaryKey() { return $this->getKey(); } public static function getBehaviorMadiafileAttributes(): array { return [SaveProcessor::FILE_TYPE_THUMB, SaveProcessor::FILE_TYPE_IMAGE]; } public static function getBehaviorAlbumAttributes(): array { return [AlbumTyped::ALBUM_TYPE_IMAGE]; } public static function getBehaviorAttributes(): array { return array_merge(static::getBehaviorMadiafileAttributes(), static::getBehaviorAlbumAttributes()); } protected static function booted(): void { $behaviorMediafile = BehaviorMediafile::getInstance(static::getBehaviorMadiafileAttributes()); $behaviorAlbum = BehaviorAlbum::getInstance(static::getBehaviorAlbumAttributes()); static::saved(function (Model $ownerModel) use ($behaviorMediafile, $behaviorAlbum) { if ($ownerModel->wasRecentlyCreated) { $behaviorMediafile->link($ownerModel); $behaviorAlbum->link($ownerModel); } else { $behaviorMediafile->refresh($ownerModel); $behaviorAlbum->refresh($ownerModel); } }); static::deleted(function (Model $ownerModel) use ($behaviorMediafile, $behaviorAlbum) { $behaviorMediafile->clear($ownerModel); $behaviorAlbum->clear($ownerModel); }); } }
主要规则
-
非常重要,必须从
BeingOwnerInterface
实现! -
非常重要,必须使用
OwnerBehavior
特性。一些由BeingOwnerInterface
要求的 BASE 方法已经存在于这个特性中。 -
非常重要,必须创建以下方法:
getItsName()
,getPrimaryKey()
。 -
非常重要,必须添加带有行为实例的
booted()
方法。 -
非常重要,必须使用具有用于 FileSetter 的属性列表的
getBehaviorAttributes()
。
查看核心更深入,想象一下它是如何工作的 :-)
继续...
非常重要,必须正确使用您的应用程序 blade 表单中的 MFU blade 部分正确!
以下是使用 blade 表单的快捷示例
uploader::partials.thumbnail
,
uploader::partials.new-mediafiles
,
uploader::partials.existing-mediafiles
,
uploader::partials.albums-form-list
:
<form action="{{ route('admin_product_store') }}" method="post"> <div class="row"> <div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-4"> @include('uploader::partials.thumbnail', ['model' => $model ?? null, 'ownerParams' => $ownerParams ?? null]) </div> </div> <div class="row"> <div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-4"> <div class="form-group"> <label for="id_title">Title</label> <input id="id_title" type="text" class="form-control @if ($errors->has('title')) is-invalid @endif" name="title" value="{{ old('title', !empty($model) ? $model->title : null) }}" required autofocus> @if ($errors->has('title')) <div class="invalid-feedback"> <strong>{{ $errors->first('title') }}</strong> </div> @endif </div> </div> </div> .......... .......... <hr /> <h5>{{ trans('uploader::main.new_files') }}</h5> <div class="row mb-3"> @include('uploader::partials.new-mediafiles', [ 'fileType' => \Itstructure\MFU\Processors\SaveProcessor::FILE_TYPE_IMAGE, 'ownerParams' => $ownerParams ?? null ]) </div> @if(!empty($edition)) <hr /> <h5>{{ trans('uploader::main.existing_files') }}</h5> <div class="row mb-3"> @include('uploader::partials.existing-mediafiles', [ 'edition' => true, 'fileType' => \Itstructure\MFU\Processors\SaveProcessor::FILE_TYPE_IMAGE, 'ownerParams' => $ownerParams ?? null, 'mediaFiles' => $mediaFiles ?? [] ]) </div> @endif @if(!empty($allImageAlbums) && !$allImageAlbums->isEmpty()) <hr /> <h5>{{ trans('uploader::main.image_albums') }}</h5> <div class="row mb-3"> @include('uploader::partials.albums-form-list', [ 'albums' => $allImageAlbums, 'edition' => true ]) </div> @endif <button class="btn btn-primary" type="submit">Create</button> <input type="hidden" value="{!! csrf_token() !!}" name="_token"> </form>
为了澄清
通过 fileType
将设置一个字段 image[]
,它将由 Itstructure\MFU\Traits\OwnerBehavior
特性中的 fill()
方法使用 getBehaviorAttributes()
设置,然后将其值放入在 booted()
调用后保存的 Product
的 BehaviorMediafile
对象中。然后,将填充表 owners_mediafiles
。将在 Product
和 Mediafile
之间创建链接。
产品编辑页面示例看起来像这样
要了解该示例在全局中的工作方式,请在此处查看真实示例: Laravel Microshop Simple。
我希望您会对这个包感到满意。祝您开发顺利!
敬上,Andrey!
许可证
版权所有 © 2024 Andrey Girnik girnikandrey@gmail.com。
遵循MIT许可协议。详情请参阅LICENSE.txt文件。