【2024年版】LaravelでIntervention Imageを使う方法

## 概要

PHPの画像処理ライブラリである**Intervention Image**の**バージョン３**を**Laravel**で使う方法について解説します。

先日、Qiitaの質問で「Intervention Imageがエラーで使えない」というものがありました。私も使ったことがあるので調べてみたのですが、どうやら2023年12月にバージョン２から３へアップデートされたようです。そして、それによって「Laravel Intervention Image」といったキーワード検索でヒットする記事の情報では導入できなくなってしまったので、この記事を執筆することにしました。

https://image.intervention.io/v3

## Intervention Imageのバージョンアップについて

https://image.intervention.io/v3/introduction/upgrade

上記のアップグレードガイドを参照すると、次のように記載されています。

> Intervention Image 3 は、以前のバージョンから引き継がれたコードがほとんどなく、根本から書き直されました。これは、PHP 8 以降の最新の機能を活用した、より現代的で洗練されたアーキテクチャと API を意味します。（機械翻訳）

このようにバージョン２から３へアップデートされるにあたって大幅に変更されたようです。さらにLaravelのサポートについては次のように記載されています。

> Laravel のサービスプロバイダーは、フレームワークへの依存を回避し、以前からそうであったフレームワークに依存しない介入イメージを強調するために削除されました。（機械翻訳）

このように、バージョン２に同梱されていたLaravelのサービスプロバイダーはバージョン３では削除されました。既存の記事ではこのサービスプロバイダーを用いた方法が説明されていたので、それをバージョン３で記事のとおりにやってみてもうまくいかないというわけですね。

その他にもさまざまな変更があるので、古いバージョンの情報を参照されている場合はアップグレードガイドを一読されることをお勧めします。

## バージョン２のLaravelサービスプロバイダーについて

バージョン２の「Laravel のサービスプロバイダー」についてもう少し触れておきましょう。既存の記事には次のような記載が見られます。

```php:既存の記事に見られるコード
'providers' => [
    Intervention\Image\ImageServiceProvider::class
],
'aliases' => [
    'Image' => Intervention\Image\Facades\Image::class
]
```

ここにある`Intervention\Image\ImageServiceProvider`や`Intervention\Image\Facades\Image`が「フレームワークへの依存を回避する」という理由から削除されました。これらの設定を追加しても、残念ながらnot foundエラーが発生して動くことはありません。

それではIntervention Imageのバージョン３をLaravelで使う方法を見ていきましょう。

## バージョン３をLaravelで使う方法

まずはドキュメントを参照して、Composerを介してインストールするところまで進めてください。そしてインストールが完了したら`composer.json`ファイルや`composer.lock`ファイルを見て`intervention/image`のバージョン３がインストールされていることを確認してください。

https://image.intervention.io/v3/introduction/installation

### 方法１　サービスプロバイダーを使わない

LaravelでIntervention Imageを使うにあたり、サービスプロバイダー使う方法は必須ではありません。例えば下記のコードはLaravelのコントローラーで使用する例ですが、ほとんどドキュメントと同じであることに気がつくでしょう。

```php:app/Http/Controllers/ImageController.php
<?php

namespace App\Http\Controllers;

use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver;

class ImageController extends Controller
{
    public function index()
    {
        // 希望するドライバーで新しいマネージャー インスタンスを作成する
        $manager = new ImageManager(new Driver());

        // 画像を垂直に反転し、別名で保存する例
        $imgPath = storage_path('app/public/hoge.png');
        $img = $manager->read($imgPath);
        $img->flop();
        $img->save(storage_path('app/public/hoge-flip.png'));
    }
}
```

ただし、複数の箇所でIntervention Imageを使う場合、この方法ではマネージャー インスタンスを作成することが冗長に感じるかもしれません。次の例を見てください。

```php:HogeController
use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver;

class HogeController extends Controller
{
    public function index()
    {
        $manager = new ImageManager(new Driver());
        // ...
    }
}
```

```php:FugaController
use Intervention\Image\ImageManager;
use Intervention\Image\Drivers\Gd\Driver;

class FugaController extends Controller
{
    public function index()
    {
        $manager = new ImageManager(new Driver());
        // ...
    }
}
```

このように複数の場所で利用する場合、同じような処理を書くことになります。このような状態で、例えばドライバーをGDからImagickに変更したい時は複数の箇所を漏れなく変更する必要があります。こういった状況になる場合は、Laravelのサービスプロバイダーを使う方法が選択肢としてあがるかもしれません。

### 方法２　サービスプロバイダーを使う

まず最初に目指すところを確認しましょう。

```php:例えばこのように使用したい
use Intervention\Image\ImageManager;

class ImageController extends Controller
{
    public function index(ImageManager $manager)
    {
        $img = $manager->read(
            storage_path('app/public/hoge.png')
        );
    }
}
```

このようにサービスを注入する形にすることによって、`ImageManager`のインスタンス生成を省きたと思います。そのために、サービスプロバイダー[^1]を利用して`ImageManager`をサービスとして登録しましょう。
[^1]:https://readouble.com/laravel/10.x/ja/providers.html


まずは`make:provider`Artisanコマンドでプロバイダーを生成します。そして、サービスコンテナ[^2]に結合していきます。
[^2]:https://readouble.com/laravel/10.x/ja/container.html

```php:app/Providers/ImageServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Intervention\Image\Drivers\Gd\Driver;
use Intervention\Image\ImageManager;

class ImageServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(ImageManager::class, function () {
            return new ImageManager(new Driver());
        });
    }
}
```

サービスプロバイダーを作成した後は`config/app.php`で登録します。

```php:config/app.php
    'providers' => ServiceProvider::defaultProviders()->merge([
        // ...
        App\Providers\ImageServiceProvider::class,
    ])->toArray(),
```

これでサービスプロバイダーがアプリケーションにロードされ、コントローラーにサービスとして注入されるようになりました。

さて改めて「ドライバーをGDからImagickに変更したい場合」を考えてみましょう。サービスプロバイダーを利用することによって、`ImageManager`のインスタンス生成はおこなわれているので、一箇所を変更するだけで済みます。

## まとめ

2023年12月に**Intervention Image**がバージョン３にアップデートされたことにより、大幅な変更がありました。そのため、**Laravel**での使い方を紹介した記事の情報が古いものになってしまいました。

これからLaravelでIntervention Imageを使う方にとって、この記事の情報が参考になれば幸いです。

## おまけ

Intervention Imageを使うためのサービスプロバイダをパッケージとして公開してみました。

https://github.com/blue32a/laravel-intervention-image