Filament Spatie Media Library 插件实战指南在 Laravel 管理后台中集成媒体库上传、缩略图与富文本附件【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filamentFilament 的spatie-laravel-media-library-plugin将 Laravel 生态中最流行的媒体管理包spatie/laravel-medialibrary无缝接入 Filament 的表单Forms、表格Tables与信息列表Infolists三大体系让开发者无需手写媒体管理逻辑即可完成文件上传、媒体集合归类、图片转换conversion、响应式图片生成、媒体排序与富文本附件等能力。本文以 插件 README 为核心骨架结合仓库源码与测试用例深入讲解每一个配置项的底层行为读完即可在自己的 Filament 管理后台中落地一套完整、可复用的媒体库方案。一、安装与模型准备1. 通过 Composer 安装插件composer require filament/spatie-laravel-media-library-plugin:^4.0 -W该插件要求 PHP^8.2并依赖spatie/laravel-medialibrary^11.0同时与 Filament 核心包保持版本一致见 composer.json。-W参数会同时升级依赖链中需要更新的包避免版本冲突。2. 发布并执行媒体表迁移Spatie 媒体库需要一张media表来存储文件元数据先发布迁移文件php artisan vendor:publish --providerSpatie\MediaLibrary\MediaLibraryServiceProvider --tagmedialibrary-migrations然后执行迁移php artisan migrate3. 准备 Eloquent 模型需要为要挂载媒体的模型实现 Spatie 的HasMedia接口并引入InteractsWithMediatrait同时按 Spatie 规范注册媒体集合media collection。例如在User模型上注册avatars集合use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\InteractsWithMedia; use Spatie\MediaLibrary\MediaCollections\Models\Media; class User extends Model implements HasMedia { use InteractsWithMedia; public function registerMediaConversions(?Media $media null): void { $this-addMediaConversion(thumb) -width(368) -height(232) -sharpen(10); } }模型准备是 Spatie 包的职责范畴完整说明可参考 Spatie 官方文档Filament 插件只负责把媒体库的能力暴露为 UI 组件。二、表单组件SpatieMediaLibraryFileUpload媒体库文件上传字段的用法与原生的 Filament 文件上传字段一致直接替换即可use Filament\Forms\Components\SpatieMediaLibraryFileUpload; SpatieMediaLibraryFileUpload::make(avatar)从源码看SpatieMediaLibraryFileUpload 继承自 Filament 基础上传字段FileUpload位于 BaseFileUpload因此它天然继承原生上传组件所有的定制能力如image()、multiple()、maxSize()、acceptedFileTypes()等。同时它在setUp()中完成了一系列媒体库专属的钩子注入loadStateFromRelationshipsUsing()从模型关联的media关系中按集合名加载媒体以uuid作为状态值saveRelationshipsUsing()先调用deleteAbandonedFiles()清理已移除的媒体再调用saveUploadedFiles()保存新文件默认dehydrated(false)字段状态不写入表单数据媒体关系由钩子自行维护。1. 使用媒体集合归类文件媒体集合collection用于把同一模型上的文件按类别分组例如头像归入avatars、附件归入attachmentsSpatieMediaLibraryFileUpload::make(avatar) -collection(avatars)不传collection()时默认使用default集合。源码中getCollection()通过evaluate()解析因此支持闭包动态返回集合名——测试用例中也验证了collection(static fn (): string dynamic)这种写法见 SpatieMediaLibraryFileUploadTest。2. 存储磁盘与目录的确定规则默认情况下文件会上传到 Filament 配置文件中定义的公共磁盘。可以在 config/filament.php 中看到默认值default_filesystem_disk env(FILESYSTEM_DISK, local),即通过FILESYSTEM_DISK环境变量即可全局切换上传磁盘。这一点与 Spatie 包自身的磁盘配置不同除非你在注册媒体集合时为集合显式指定了磁盘否则 Spatie 的磁盘配置不会被采用。源码中getDiskName()的解析顺序印证了这一规则手动通过disk()指定的磁盘名模型上已注册媒体集合中同名集合的diskName回退到config(filament.default_filesystem_disk)。同时源码还处理了一个特例当解析出的磁盘是public而字段显式要求private可见性时会自动改用local磁盘以保证私有文件不会落入公共磁盘。如果需要手动指定磁盘可以在基础上传字段上调用disk()use Filament\Forms\Components\FileUpload; FileUpload::make(attachment) -disk(s3)需要特别注意的是基础上传字段的directory()上传目录和visibility()可见性选项对媒体库上传字段不生效。Spatie 包有自己的目录生成机制且默认不支持私有文件上传。如果要实现私有存储建议在 S3 存储桶侧配置访问策略同时配合visibility(private)此时 Filament 会为文件生成临时 URL。源码中可见当getVisibility() private时组件会调用$media-getTemporaryUrl(...)过期时间取自config(filament.temporary_file_url_expiry_minutes, 30)默认 30 分钟见 config/filament.php并在驱动不支持临时 URL 时优雅降级。3. 多文件拖拽排序Spatie 媒体库本身支持对集合内文件排序插件通过reorderable()开放这一能力SpatieMediaLibraryFileUpload::make(attachments) -multiple() -reorderable()开启后用户可以直接拖拽文件调整顺序。底层由reorderUploadedFilesUsing()钩子实现组件收集表单当前状态中的 uuid 列表与记录现有媒体对比过滤后调用媒体模型的setNewOrder()更新order_column排序字段见 SpatieMediaLibraryFileUpload.php。测试中通过先上传两个文件再模拟拖拽交换顺序验证了排序结果的正确性见 SpatieMediaLibraryFileUploadTest。4. 自定义属性customPropertiescustomProperties()允许在文件上传时写入自定义元数据例如记录 zip 文件名的前缀SpatieMediaLibraryFileUpload::make(attachments) -multiple() -customProperties([zip_filename_prefix folder/subfolder/])自定义属性同样支持闭包并且闭包可以接收上传的临时文件参数从而根据文件内容动态计算属性。比如在上传图片时自动读取宽高use Filament\Forms\Components\SpatieMediaLibraryFileUpload; use Livewire\Features\SupportFileUploads\TemporaryUploadedFile; use Spatie\Image\Image; SpatieMediaLibraryFileUpload::make(image) -image() -customProperties(function (TemporaryUploadedFile $file): array { $image Image::load($file-getRealPath()); return [ height $image-getHeight(), width $image-getWidth(), ]; })源码中getCustomProperties()在求值闭包时注入了file参数所以闭包签名可以声明TemporaryUploadedFile $file见 SpatieMediaLibraryFileUpload.php。保存时这些属性会通过withCustomProperties()写入媒体记录。5. 自定义请求头customHeaders当文件上传到云存储如 S3时可以通过customHeaders()为上传请求附加自定义请求头SpatieMediaLibraryFileUpload::make(attachments) -multiple() -customHeaders([CacheControl max-age86400])源码在保存文件时会合并默认请求头与自定义请求头addCustomHeaders([...[ContentType $file-getMimeType()], ...$component-getCustomHeaders()])即ContentType由系统根据 MIME 类型自动填充其余请求头完全由customHeaders()控制见 SpatieMediaLibraryFileUpload.php。6. 生成响应式图片responsiveImagesresponsiveImages()让媒体库在上传图片时自动生成多个尺寸的响应式图片供不同屏幕宽度加载合适资源SpatieMediaLibraryFileUpload::make(attachments) -multiple() -responsiveImages()该选项直接映射到 Spatie 的withResponsiveImagesIf()方法默认值为false可通过闭包动态控制测试中验证了responsiveImages(static fn (): bool true)的写法。7. 使用图片转换conversion如果模型注册了图片转换如缩略图可以指定表单展示时优先加载哪一个转换版本SpatieMediaLibraryFileUpload::make(attachments) -conversion(thumb)底层逻辑位于getUploadedFileUsing()组件先从媒体记录中按 uuid 找到对应 Media然后按以下优先级确定展示 URL若字段为私有可见性尝试生成临时 URL并优先使用已生成的转换若指定了conversion()且该转换已生成使用转换后的 URL回退到原图 URL见 SpatieMediaLibraryFileUpload.php。将转换与响应式图片存到独立磁盘转换和响应式图片可以与原文件分开存储通过conversionsDisk()指定目标磁盘SpatieMediaLibraryFileUpload::make(attachments) -conversionsDisk(s3)保存时该磁盘名会传递给storingConversionsOnDisk()例如把原图存在本地、把缩略图存在 S3以降低本地存储压力。8. 存储媒体专属处理参数manipulationsmanipulations()用于存储仅针对该媒体的图像处理指令区别于模型级注册的转换。这些指令会在文件上传时执行SpatieMediaLibraryFileUpload::make(attachments) -multiple() -manipulations([ thumb [orientation 90], ])例如上面的配置会在生成thumb转换时把图片旋转 90 度。该数组通过withManipulations()写入媒体记录属于媒体实例级media-specific的操作。9. 过滤集合内的媒体filterMediaUsingfilterMediaUsing()可以让上传字段只处理集合内满足条件的媒体子集回调接收一个Illuminate\Support\Collection并返回过滤后的集合可以使用任意 Laravel Collection 方法。典型场景是按自定义属性做范围限定例如只处理属于某个相册gallery的图片use Filament\Schemas\Components\Utilities\Get; use Filament\Forms\Components\SpatieMediaLibraryFileUpload; use Illuminate\Support\Collection; SpatieMediaLibraryFileUpload::make(images) -customProperties(fn (Get $get): array [ gallery_id $get(gallery_id), ]) -filterMediaUsing( fn (Collection $media, Get $get): Collection $media-where( custom_properties.gallery_id, $get(gallery_id) ), )该能力由共享 trait HasMediaFilter 提供filterMediaUsing()保存回调filterMedia()在求值时注入media参数并返回结果。这个 trait 同时被表单上传字段、表格图片列与信息列表图片条目复用保证三端过滤行为一致。加载媒体、保存清理和删除清理三个阶段都会应用该过滤器确保用户只会看到和操作自己范围内的媒体。三、表格列SpatieMediaLibraryImageColumn在资源列表页展示媒体库图片使用SpatieMediaLibraryImageColumnuse Filament\Tables\Columns\SpatieMediaLibraryImageColumn; SpatieMediaLibraryImageColumn::make(avatar)该列继承自基础图片列ImageColumn因此支持原生图片列的所有定制项circular()、stacked()、width()、height()、extraImgAttributes()等用法与基础图片列完全一致源码见 SpatieMediaLibraryImageColumn。1. 指定媒体集合与全部集合默认情况下列只展示default集合中的媒体通过collection()可切换到指定集合SpatieMediaLibraryImageColumn::make(avatar) -collection(avatars)如果希望展示模型上所有集合的媒体使用allCollections()SpatieMediaLibraryImageColumn::make(avatar) -allCollections()从源码看allCollections()内部把集合设为AllMediaCollections标记对象见 AllMediaCollections.phpgetState()在遍历媒体时遇到该标记即跳过按集合名过滤的逻辑从而聚合所有集合。2. 加载转换版本与表单字段类似表格列也可以通过conversion()优先展示转换后的图片SpatieMediaLibraryImageColumn::make(avatar) -conversion(thumb)getImageUrl()中指定转换且已生成时调用getAvailableUrl()返回转换 URL私有可见性下则改为生成临时 URL见 SpatieMediaLibraryImageColumn.php。此外setUp()中还注册了defaultImageUrl()兜底逻辑当记录没有对应媒体时调用 Spatie 的getFallbackMediaUrl()返回默认占位图。3. 按条件过滤展示列同样支持filterMediaUsing()例如只展示指定gallery_id的图片use Filament\Tables\Columns\SpatieMediaLibraryImageColumn; use Illuminate\Support\Collection; SpatieMediaLibraryImageColumn::make(images) -filterMediaUsing( fn (Collection $media): Collection $media-where( custom_properties.gallery_id, 12345, ), )源码还会为列自动启用媒体关系的预加载applyEagerLoading()中with([media fn ($query) $query-ordered()])按order_column排序避免 N1 查询见 SpatieMediaLibraryImageColumn.php。测试用例覆盖了collection()、allCollections()、conversion()与filterMediaUsing()的字符串、闭包与置空三种形态见 SpatieMediaLibraryImageColumnTest。四、信息列表条目SpatieMediaLibraryImageEntry在查看详情页View Page或信息列表Infolist中展示媒体图片使用SpatieMediaLibraryImageEntryuse Filament\Infolists\Components\SpatieMediaLibraryImageEntry; SpatieMediaLibraryImageEntry::make(avatar)它继承自基础图片条目ImageEntry支持原生图片条目的全部定制项用法与表格列几乎对称源码见 SpatieMediaLibraryImageEntry// 指定集合 SpatieMediaLibraryImageEntry::make(avatar) -collection(avatars) // 展示所有集合 SpatieMediaLibraryImageEntry::make(avatar) -allCollections() // 展示转换版本 SpatieMediaLibraryImageEntry::make(avatar) -conversion(thumb) // 按自定义属性过滤 SpatieMediaLibraryImageEntry::make(images) -filterMediaUsing( fn (Collection $media): Collection $media-where( custom_properties.gallery_id, 12345, ), )与表格列一致默认只展示default集合allCollections()聚合全部集合私有可见性下自动使用临时 URL同样注册了getFallbackMediaUrl()兜底逻辑。三种展示组件在 API 设计上的高度统一意味着你可以在表单、列表、详情三处用几乎相同的代码完成媒体展示。五、富文本编辑器附件SpatieMediaLibraryFileAttachmentProvider富文本编辑器RichEditor详见 Filament 表单文档支持使用媒体库存储其中的文件附件。做法是在模型上注册富文本内容属性rich content attribute并为属性指定fileAttachmentProvider()传入SpatieMediaLibraryFileAttachmentProvider::make()use Filament\Forms\Components\RichEditor\FileAttachmentProviders\SpatieMediaLibraryFileAttachmentProvider; use Filament\Forms\Components\RichEditor\Models\Concerns\InteractsWithRichContent; use Filament\Forms\Components\RichEditor\Models\Contracts\HasRichContent; use Illuminate\Database\Eloquent\Model; class Post extends Model implements HasRichContent { use InteractsWithRichContent; public function setUpRichContent(): void { $this-registerRichContent(content) -fileAttachmentProvider(SpatieMediaLibraryFileAttachmentProvider::make()); } }使用SpatieMediaLibraryFileAttachmentProvider时富文本属性上例中的content必须在数据库中定义为可空nullable。1. 附件媒体集合的命名规则附件默认存放在与属性同名的媒体集合中上例为content。该集合只能存放该属性的附件因为模型保存时 Filament 会调用clearMediaCollectionExcept()清空集合内未被引用的媒体见 SpatieMediaLibraryFileAttachmentProvider.php。如果不想与属性同名可以自定义集合名$this-registerRichContent(content) -fileAttachmentProvider( SpatieMediaLibraryFileAttachmentProvider::make() -collection(content-file-attachments), );2. 保留原始文件名默认情况下附件保存时会使用 ULID 重命名文件Str::ulid() . . . $file-getClientOriginalExtension()。如需保留用户上传的原始文件名调用preserveFilenames()SpatieMediaLibraryFileAttachmentProvider::make() -preserveFilenames()3. 自定义媒体名称mediaName()可以定制媒体记录的名称字段name与文件名 file_name 不同支持基于上传文件动态生成use Filament\Forms\Components\RichEditor\FileAttachmentProviders\SpatieMediaLibraryFileAttachmentProvider; use Livewire\Features\SupportFileUploads\TemporaryUploadedFile; use Illuminate\Support\Str; SpatieMediaLibraryFileAttachmentProvider::make() -mediaName(fn (TemporaryUploadedFile $file): string Str::random() . _ . $file-getClientOriginalName())4. 写入自定义属性附件同样支持customProperties()SpatieMediaLibraryFileAttachmentProvider::make() -customProperties([archived false])从源码看provider 实现还包含两个值得注意的默认行为默认附件可见性为privategetDefaultFileAttachmentVisibility()返回private即富文本附件默认按私有文件处理、使用临时 URL 展示同时isExistingRecordRequiredToSaveNewFileAttachments()返回true意味着只有已存在的记录才能保存新附件因此在新建记录场景下需要先创建记录再编辑富文本内容。六、写在最后通过 Form、Table、Infolist 三端组件与富文本附件 Provider 的组合Filament 的 Spatie Media Library 插件将媒体库的「上传 → 归类 → 转换 → 展示 → 清理」全流程封装为声明式 API表单端SpatieMediaLibraryFileUpload继承基础上传字段的全部能力并额外提供collection()、reorderable()、customProperties()、customHeaders()、responsiveImages()、conversion()、conversionsDisk()、manipulations()、filterMediaUsing()九个媒体库专属方法展示端SpatieMediaLibraryImageColumn与SpatieMediaLibraryImageEntry在基础图片列/条目的能力之上统一提供collection()、allCollections()、conversion()、filterMediaUsing()并自动处理预加载、排序、私有文件临时 URL 与占位图兜底富文本端SpatieMediaLibraryFileAttachmentProvider让富文本附件直接落库到媒体集合支持集合改名、原始文件名保留、自定义媒体名与自定义属性。所有配置均可传入闭包动态求值与 Filament 的组件体系保持一致HasMediaFiltertrait 的复用保证了三个展示/上传场景的过滤行为完全一致而 插件测试目录 中的三份测试文件则覆盖了每个方法的基础、闭包与重置传入null形态可作为集成时的行为参考。上手时只要记住两点磁盘遵循 Filament 的default_filesystem_disk配置而非 Spatie 默认磁盘directory()/visibility()对媒体库上传不生效私有文件需配合存储侧策略与visibility(private)使用即可避免绝大多数踩坑场景。【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filament创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考