Media Library(管理檔案與媒體檔案)

套件簡介:spatie/laravel-medialibrary

spatie/laravel-medialibrary 是一個功能強大的 Laravel 套件,用於處理檔案的上傳與管理,支援圖片、PDF、文件等格式。它的核心設計是讓模型能夠與媒體檔案建立關聯,實現:

  • 將媒體檔案儲存至指定磁碟(如 publiclocal 或 Amazon S3)
  • 管理與模型關聯的媒體檔案
  • 自動產生圖片縮圖(Conversions)
  • 支援多個媒體集合(如 imagesdownloads
  • 自動產生檔案的 URL 與實體路徑

範例:

$post->addMedia($file)->toMediaCollection('images');
Laravel 模型 儲存檔案用途
Post 多張圖片
User 頭像圖片
Product 圖片與說明文件

安裝步驟

composer require spatie/laravel-medialibrary

# 建立媒體資料表
php artisan vendor:publish --tag="media-library-migrations"
php artisan migrate

# 發布設定檔
php artisan vendor:publish --tag="media-library-config"

基本使用方式

1. 在模型中加入介面與 Trait

use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class Post extends Model implements HasMedia
{
    use InteractsWithMedia;
}

2. 上傳媒體至特定集合

$post = Post::find(1);

$post->addMedia($request->file('image'))
     ->toMediaCollection('images');

3. 取得媒體集合

$mediaItems = $post->getMedia('images');

foreach ($mediaItems as $media) {
    echo $media->getUrl();
}

圖片轉換(自動產生縮圖)

使用圖片轉換功能需額外安裝圖片處理套件,如 intervention/imagespatie/image

composer require intervention/image
use Spatie\MediaLibrary\MediaCollections\Models\Media;

public function registerMediaConversions(Media $media = null): void
{
    $this->addMediaConversion('thumb')
         ->width(368)
         ->height(232)
         ->sharpen(10);
}

// 取得縮圖 URL
$media->getUrl('thumb');

指定儲存磁碟(如 S3)

$post->addMedia($file)
     ->toMediaCollection('downloads', 's3');

常用方法彙整

方法 說明
addMedia() 上傳並關聯媒體檔案
toMediaCollection('images') 指定集合名稱
getMedia('images') 取得媒體集合
getFirstMedia('images') 取得集合中的第一筆媒體
clearMediaCollection('images') 清除指定媒體集合
getUrl() 取得媒體的公開 URL
getPath() 取得媒體的實體路徑
media() Eloquent 關聯,可查詢媒體

實務應用場景

應用場景 說明
使用者上傳頭像 使用 User 模型搭配 avatar 集合
商品多圖上傳 使用 Product 模型搭配 images 集合
文件下載 將 PDF 上傳至 downloads 集合
圖片縮圖與顯示 自動產生縮圖,提升載入效率

Post 模型完整範例

步驟一:安裝套件與設定

composer require spatie/laravel-medialibrary
php artisan vendor:publish --tag="media-library-migrations"
php artisan migrate
php artisan vendor:publish --tag="media-library-config"

步驟二:建立 Post 模型與資料表

php artisan make:model Post -m
// database/migrations/xxxx_xx_xx_create_posts_table.php

Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->timestamps();
});

php artisan migrate

步驟三:修改 Post 模型支援媒體功能

// app/Models/Post.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;

class Post extends Model implements HasMedia
{
    use InteractsWithMedia;

    protected $fillable = ['title'];

    public function registerMediaConversions(Media $media = null): void
    {
        $this->addMediaConversion('thumb')
             ->width(300)
             ->height(300)
             ->sharpen(10);
    }
}

步驟四:建立 PostController

php artisan make:controller PostController
// app/Http/Controllers/PostController.php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function store(Request $request)
    {
        $request->validate([
            'title' => 'required|string',
            'image' => 'required|image|max:2048',
        ]);

        $post = Post::create([
            'title' => $request->title,
        ]);

        $post->addMedia($request->file('image'))
             ->toMediaCollection('images');

        return response()->json(['message' => 'Post created']);
    }

    public function show(Post $post)
    {
        $media = $post->getFirstMedia('images');

        return response()->json([
            'title' => $post->title,
            'image_url' => $media?->getUrl(),
            'thumb_url' => $media?->getUrl('thumb'),
        ]);
    }
}

步驟五:新增路由設定

// routes/web.php 或 routes/api.php

use App\Http\Controllers\PostController;

Route::post('/posts', [PostController::class, 'store']);
Route::get('/posts/{post}', [PostController::class, 'show']);

額外提醒

若使用 public disk,需建立符號連結:

php artisan storage:link