【Laravel】macroでコレクションに汎用メソッドを追加する

こんにちは。突然ですが皆さんはLaravelのコレクションを使っていて、つぎのような経験をしたことはありますか?

  • 必要としているメソッドが存在しない

このような時、あなたならどうしますか?独自の汎用クラスを作ることを検討しますか?勿論それも正解です。しかし、クラスが増えてくるにつれて、モジュールのインポートが煩雑になり、管理が大変になったりしていませんか?今回はそんな悩みを解決するための方法を紹介します。

macroでコレクションを拡張する

Laravelのコレクションは拡張することができます。具体的にいうと、コレクションの実装には影響を与えずに、コレクションに独自のメソッドを追加することができるのです。試しに小文字を大文字に変換するtoUpperメソッドを作成してみました。早速使ってみましょう。

$sample = collect(['first','second']);
$sample->toUpper();
// ["FIRST", "SECOND"]

まるでコレクションにtoUpperメソッドがもともと存在しているかのように呼び出すことができます。では、どのように実装しているのか紹介します。次のコードです。

use Illuminate\Support\Collection;
use Illuminate\Support\Str;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Collection::macro('toUpper', function () {
    		return $this->map(function ($value) {
        		return Str::upper($value);
    		});
		});
    }

アプリケーションのロード時に実行する必要があるので、AppServiceProviderのbootメソッド内に記述します。コレクションにメソッドを追加するには、Collectionファサードのmacroメソッドを使用します。第一引数にはメソッドの名前を指定し、第二引数で実際に実行する処理をクロージャで渡します。このクロージャの中に、独自の処理を記述していくことになります。クロージャ内では$thisを使用してコレクションのインスタンスにアクセスすることができます。

まとめ

今回はmacroでコレクションを拡張する方法を解説しました。汎用的な処理をmacroで定義しておけば、様々なLaravelプロジェクトで使いまわしができるようになると思います。汎用的な処理が出てきたら面倒臭がらずにmacro化を検討してみると良いと思います。

参考

Laravel公式ドキュメント コレクション https://readouble.com/laravel/8.x/ja/collections.html

Laravel

Posted by kobainmac