【Laravel】View Composer 実践ガイド:全ページ共通データをスマートに渡す方法

Laravel

LaravelでブログやWebアプリを開発していると、「すべてのページのサイドバーに最新のカテゴリー一覧を表示したい」「ヘッダーに常にユーザーの通知件数を表示したい」といった要件に必ず直面します。

これをすべてのコントローラーに書いてしまうと、コードが重複し、保守性が著しく低下します。本記事では、この問題を解決するView Composer(ビューコンポーサー)の具体的な実装手順を、最新のLaravel12環境に合わせて解説します。

今回は「サイドバー(partials.sidebar)に、常にカテゴリー一覧データを渡す」という要件を例に実装を進めます。

Step 1: 専用のServiceProviderを作成する

View Composerを登録するためには、専用のServiceProviderを作成するのがベストプラクティスです。Artisanコマンドを使うことで、ファイルの生成から登録までを自動化できます。

ターミナルで以下のコマンドを実行します。

Bash
php artisan make:provider ViewServiceProvider

現在のスリム化されたディレクトリ構造では、このコマンドを実行するだけで自動的に bootstrap/providers.php にプロバイダが追記されます。念の為、ファイルを開いて正しく登録されているか確認してみましょう。

bootstrap/providers.php

PHP
<?php

return [
    App\Providers\AppServiceProvider::class,
    App\Providers\ViewServiceProvider::class, // ← 自動的に追記されています
];

Step 2: Composer クラスを作成する

次に、実際にデータを取得してViewに渡すロジックを持つ「Composerクラス」を作成します。 app/View/Composers というディレクトリを新規作成し、その中に SidebarComposer.php を作成します。

app/View/Composers/SidebarComposer.php

PHP
<?php

namespace App\View\Composers;

use Illuminate\View\View;
use App\Models\Category;

class SidebarComposer
{
    /**
     * データをビューに結合する
     *
     * @param  \Illuminate\View\View  $view
     * @return void
     */
    public function compose(View $view)
    {
        // カテゴリー一覧を取得(例として、記事数が多い順に5件)
        $categories = Category::withCount('posts')
            ->orderBy('posts_count', 'desc')
            ->take(5)
            ->get();

        // 'categories' という変数名でViewに渡す
        $view->with('categories', $categories);
    }
}

このようにデータ取得のロジックをクラスに分離することで、コントローラーが肥大化する(Fat Controller)のを防ぐことができます。

Step 3: ViewServiceProvider で紐付ける

先ほど作成した ViewServiceProviderboot メソッド内で、「どのViewが表示されるときに」「どのComposerクラスを呼び出すか」を宣言します。

app/Providers/ViewServiceProvider.php

PHP
<?php

namespace App\Providers;

use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use App\View\Composers\SidebarComposer;

class ViewServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        //
    }

    public function boot(): void
    {
        // resources/views/partials/sidebar.blade.php が呼ばれた時に
        // SidebarComposer の compose メソッドが自動実行される
        View::composer('partials.sidebar', SidebarComposer::class);

        // 複数のViewに適用したい場合は配列で指定可能
        // View::composer(['partials.sidebar', 'partials.footer'], SidebarComposer::class);
    }
}

Step 4: Blade テンプレートでの表示

あとは、対象となるBladeテンプレート側で、渡された変数 $categories を表示するだけです。データを渡すための記述はコントローラー側には一切不要です。

resources/views/partials/sidebar.blade.php

PHP
<aside class="sidebar">
    <h3>人気のカテゴリー</h3>
    <ul>
        @foreach ($categories as $category)
            <li>
                <a href="{{ route('category.show', $category) }}">
                    {{ $category->name }} ({{ $category->posts_count }})
                </a>
            </li>
        @endforeach
    </ul>
</aside>

これで、他のどのコントローラーからViewがレンダリングされても、その中に @include('partials.sidebar') が含まれていれば、自動的にカテゴリーデータが取得・表示されるようになります。

まとめ

プロバイダの登録が bootstrap/providers.php に集約・自動化されたことで、View Composerの導入が非常にスムーズになっています。

  • DRY原則の徹底: 同じデータ取得ロジックをあちこちに書く必要がなくなります。
  • 関心の分離: コントローラーは「そのページ固有の処理」に集中できます。

共通パーツのデータバインディングには、ぜひこのスマートな手法を取り入れてみてください。。

コメント