【Laravel定番シリーズ】「laravel-medialibrary」でモデルと画像の関連付け

Laravelを使ったプロジェクトでよく使うライブラリを紹介。最初となる今回は画像関連です。 ポータルサイトなどで必ずと言っていいほど必要になるのが、データと画像の紐付けです。
あるデータ1件に対してメイン画像や画像ギャラリーなどを表示する際、画像ファイルを保存しつつ、そのファイルとDBのデータとを紐付けます。

今のところ個人的に最も使い勝手が良いと思うライブラリは laravel-medialibrary なので、これを”定番”認定としたいと思います。

laravel-medialibrary

ここで紹介するのは記事公開時点のバージョン 7.5.1 です。

GitHub
ドキュメント

laravel-medialibrary にできることは、主に以下のことです。
  • アップロード画像の保存
  • アップロードした画像の読み出し
  • 画像の削除
  • アップロード画像と Model の紐付け
  • 画像のリサイズ
  • 外部サイトからの画像ダウンロード
  • レスポンシブ用画像の出力
  • 動画への対応(php-ffmpeg利用)

インストール

Composer でインストールします。
composer require spatie/laravel-medialibrary:^7.0.0
laravel-medialibrary の最新バージョンである 7 以上では Laravel 5.5 以上が必要ですので、config/app.php への Provider の追加などは必要ありません。
続いてDBマイグレーションを行います。
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="migrations"
php artisan migrate
デフォルト設定を独自に変更したい場合は設定ファイルをコピーします。
(ファイル保存先や画像最適化ツールなどを指定できます)
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="config"

モデルとの関連付け

例えば User モデルに画像を関連付けたい場合は app/User.php を以下のように変更します。
namespace App;

use Illuminate\Database\Eloquent\Model;

use Spatie\MediaLibrary\HasMedia\HasMedia; // 追加
use Spatie\MediaLibrary\HasMedia\HasMediaTrait; // 追加

class User extends Model implements HasMedia // 追加
{
    use HasMediaTrait; // 追加
   ...
}
HasMediaTrait トレイトが指定されていれば addMedia メソッドが使えるようになるので、以下のようにして画像を関連付けることができます。
use App\User;

$file = 'アップロードした画像等のパス.jpg';

$user = User::find(1);
$user->addMedia($file)->toMediaCollection();
toMediaCollection メソッドは画像をディレクトリとDBに保存する処理で、以下のようにしてグループを指定することもできます。
$user->addMedia($file)->toMediaCollection('group_name');

画像の取得

単純な取得はシンプルです。
以下は関連付けられたすべての画像を取得します。
use App\User;

$user = User::find(1);
$items = $user->getMedia();

// 特定グループのデータを取得する場合
$items = $user->getMedia('group_name');
上記の $items はLaravelの `Illuminate\Support\Collection` ですので、様々なヘルパが使えます
個々の画像では以下のような情報が取得できます。
// 相対パスの画像URL
$publicUrl = $items[0]->getUrl();

// 絶対パスの画像URL
$publicFullUrl = $items[0]->getFullUrl();

// サーバー上のフルパス
$fullPathOnDisk = $items[0]->getPath();
画像を最初の1件だけ欲しい場合は以下のメソッドが用意されています。
$media = $user->getFirstMedia();

// 最初の1件のURLのみ欲しい場合
$url = $newsItem->getFirstMediaUrl();

画像の削除

削除する場合は以下のように指定します。
use App\User;

$user = User::find(1);

// 最初の1件を削除
$user->getFirstMedia()->delete();

// 特定のものを削除
$user->getMedia()[2]->delete();

// すべて削除
$user->clearMediaCollection();

// 特定グループのみ削除
$user->clearMediaCollection('group_name');

あとがき

かなりおおまかに紹介しましたが、ほかにも便利な機能がたくさんあるので公式ドキュメントを詳しく見ることをおすすめします。

画像関連はわりと手間取ったりするため、こういったものでサクッと機能追加できるといいですね。