Help us understand the problem. What is going on with this article?

【laravel】view composerでviewロジックを分離する

More than 3 years have passed since last update.

web開発を行っていると、MVCなどのアーキテクチャ構成はとても悩ましいところです。

私がいつも思うのは
ビューロジックはできればコントローラーに書きたくないし、
テンプレートもできるだけロジックを入れず、
綺麗なhtmlのままでありたい。

実際の処理とビューのロジックが混ざってわかりづらくなってしまいますからね。

そういった問題を解決する手段として、
世の中にはプレゼンターを用意するとか、jsフレームワークを利用するとか様々なものが存在してます。

今回はlaravelに標準で搭載されているview composerの機能を紹介したいと思います。

view composerの振る舞い

view composerはいわばプレゼンターやビューモデルのような振る舞いをします。
それぞれのテンプレートに値を紐付けることができます。
仕組み自体はただこれだけなので、簡単に利用することができます。

使い方

使い方の一例を紹介してみます。
まずはコードを御覧ください。

<?php namespace App\Providers;

use App\Http\ViewComposers as V;

class ViewComposerProvider
{
    public function boot()
    {
        \View::composers([
            V\AuthComposer::class    => 'layouts.*',
            V\SideBarComposer::class => 'elements.sidebar'
        ]);
    }
}

上記はview composer用のサービスプロパイダーを作成し、view composerを登録しています。
\View::composers()で複数のクラスをbladeテンプレートに紐付けることができます。

上記の例では全てのlayoutsテンプレートにログイン情報を、
elements.sidebarテンプレートにサイドバーで必要な情報をひも付けています。

登録したクラスは例えばこのように記載します。

<?php namespace App\Http\ViewComposers;

use Illuminate\View\View;

class AuthComposer 
{
    protected $user;

    public function __construct(UserService $user)
    {
        $this->user = $user;
    }

    public function compose(View $view)
    {
        $user = $this->user->getUserInfo();

        $view->with([
            'user_id'   =>  $user->user_id,
            'user_name' => $user->user_name,
        ]);
    }
}

composerの第一引数にviewインスタンスが渡されるので、そこにwithでviewで使いたいパラメータを指定できます。

デフォルトではcomposerメソッドが呼ばれますが、
指定することもできます。

V\AuthComposer::class.'@exec' => 'layouts.*',

こんな感じでコントローラーに記載せずに直接モデル層から値を注入できます。
これをすることでコントローラーがとてもすっきり!

view creatorの挙動

view composerの他にはview creatorというものもあります。
基本的に挙動は一緒なのですが、実行されるタイミングが異なります。
簡潔に言えば、

view creatorはviewインスタンスが作成されるとき
view composerはviewインスタンスからviewがコンパイル、結合されて文字列に変換されるとき

といった違いがあります。

使い方はいたって簡単で、上記のクラスの例で言えば、composeメソッドのようにクラスを登録してからcreateメソッドを作成するだけです。

//サービスプロバイダ等で登録
// creatorsメソッドはない、、
\View::creator('layouts.*',   V\AuthComposer::class);

class AuthComposer
{
    //....

    public function  create(View $view) 
    {
        //
    }
}

view creatorとview composer挙動を詳しく理解するにはまずレンダリングの仕方を理解する必要があります。

基本的にController等で実行するとき、下記の様にするのが一般的かと思います。

class IndexController
{
    public function index()
    {
        // logic

        return view('index', [/* data */]);
    }
}

viewメソッドは何をしているかといえば、
bladeコンパイラークラスや、ビューで使用するデータを注入してViewインスタンスを返しています。
この時にview creatorが実行されます。

    // viewインスタンスが返ってくる、view creatorが実行される。
    $view = view('index', []);

controllerの戻り値は文字列に型変換されます。その際、__toString()を通してrenderメソッドが実行されます。

public function IndexController()
{
    //Viewのインスタンス
    return view('index', []);

    // 下記で返してもやってることは同じ
    // $view = view('index', []);
    return (string) $view;
    return $view->__toString();
    // 文字列が返される
    return $view->render();
}

renderメソッドではbladeが解決されたりしているのですが、この時の最初の動作として
view composerが実行されます。

つまり、実行タイミングとしては
view creator(make実行時) -> view composer(render実行時)
です。

view composerを利用してビューのロジックを分離して可読性、独立性上げていきましょう!

youkyll
Laravel → Ruby on Rails → Next.js, React Native, GraphQL
https://youkyll.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away