🦁

Laravel × Spatie Medialibrary:S3に保存するための実装手順

2025/01/14に公開

AWS上でIAMの設定とS3のバケット作成が済んでいる前提で進めていきます。

1. 必要なパッケージをインストール

必要なライブラリをインストールします。

composer require league/flysystem-aws-s3-v3
composer require spatie/laravel-medialibrary

2. Medialibrary 設定の初期化

spatie/laravel-medialibrary の設定を公開してマイグレーションを実行します。

php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider"
php artisan migrate

3. S3ドライバを設定

config/filesystems.php で S3 への接続設定をします。

'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,
],

.env ファイルに環境変数を追記します。

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=ap-northeast-1
AWS_BUCKET=

4. モデルに HasMedia トレイトを追加

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;

class Video extends Model implements HasMedia
{
    use HasFactory,
        InteractsWithMedia;

    protected $fillable = ['name'];
}

5. アップロードロジックを作成

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Video;
use Illuminate\Http\Request;

class VideoController extends Controller
{
    /**
     * 動画アップロードフォームを表示
     */
    public function create()
    {
        return view('videos.create');
    }

    /**
     * 動画を保存(S3 にアップロード)
     */
    public function store(Request $request)
    {
        // バリデーション
        $request->validate([
            'name' => 'required|string|max:255',
            'video' => 'required|file|mimes:mp4,mov,avi,wmv|max:20480', // ファイルサイズや拡張子は必要に応じて調整
        ]);

        // モデルを作成
        $video = new Video();
        $video->name = $request->input('name');
        $video->save();

        // Spatie MediaLibrary のメソッドでアップロード
        // 第2引数でアップロード先ディスクを指定("s3" など)
        $video->addMediaFromRequest('video')
              ->toMediaCollection('videos', 's3'); 

        return redirect()
            ->back()
            ->with('success', '動画をアップロードしました!');
    }
}

ポイント解説

addMediaFromRequest('video') でリクエストの video フィールドを指定しています。
toMediaCollection('videos', 's3') の第2引数でアップロード先のディスクを指定できます。

6. カスタムパス

spatie/laravel-medialibraryのデフォルト設定では[id]/[ファイル名]というディレクトリ構成でアップロードされます。

設定ファイルを作成し、任意のディレクトリ構成にしたい設定(カスタムパスジェネレータ)を書くことで変更することができます。

php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="medialibrary-config"

カスタムパスジェネレータを作成

ここでは Services\MediaLivrary\CustomMoviePathGenerator.php という名前でカスタムパスジェネレータを作成し、[コレクション名]/[id名]/[ランダム文字列.拡張子] というディレクトリ構成で保存されるように設定しました。

<?php

namespace App\Services\MediaLibrary;

use Spatie\MediaLibrary\Support\PathGenerator\PathGenerator;
use Spatie\MediaLibrary\MediaCollections\Models\Media;

class CustomMoviePathGenerator implements PathGenerator
{
    /**
     * メディアの保存パスをカスタマイズ
     */
    public function getPath(Media $media): string
    {
        // コレクション名/id名/ランダム文字列.拡張子
        return "{$media->collection_name}/".$this->getBasePath($media).'/';
    }

    /*
     * Get the path for conversions of the given media, relative to the root storage path.
     */
    public function getPathForConversions(Media $media): string
    {
        return $this->getBasePath($media).'/conversions/';
    }

    /*
     * Get the path for responsive images of the given media, relative to the root storage path.
     */
    public function getPathForResponsiveImages(Media $media): string
    {
        return $this->getBasePath($media).'/responsive-images/';
    }

    /*
     * Get a unique base path for the given media.
     */
    protected function getBasePath(Media $media): string
    {
        $prefix = config('media-library.prefix', '');

        if ($prefix !== '') {
            return $prefix.'/'.$media->getKey();
        }

        return $media->getKey();
    }
}

最後にconfig/media-libray.phpに Video モデルの場合、このカスタムパスジェネレータの設定が反映されるようにしています。

'custom_path_generators' => [
    // Model::class => PathGenerator::class
    // or
    // 'model_morph_alias' => PathGenerator::class
    Video::class => App\Services\MediaLibrary\CustomMoviePathGenerator::class,
],

Discussion