【Laravel】もう無駄なコントローラーの処理はしたくない！View Composerの使い方

こんにちは、モナ坊です!

今回は、LaravelのViewComposerについて書きます。


[前回の記事](https://qiita.com/daikidev111/items/eb376ce10891e62fa0c9)が閲覧数ほぼ6000回とプチバズりしたので、
凄くやる気溢れています。笑
良ければそちらも興味深いので是非ご覧ください！

##1. はじめに
皆さん、コントローラーで同じ値を複数のViewのファイルに受け渡していませんか？

例えば：

```PHP:AccountController.php
<?php

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;

final class AccountController extends Controller
{
	public function show1()
	{
        $user = Auth::user();
		return view('account.detail1')->with('user', $user);
	}

	public function show2()
	{
        $user = Auth::user();
		return view('account.detail2')->with('user', $user);
	}
}

```

と、同じ値($user)を複数のファイル(account.detail1　と　account.detail2)に書かないといけなくなってしまいます。
これが、２つのファイルだけでなく１０、いや１００個のファイルに受け渡すとどうなるでしょう？！（いや、大袈裟すぎ！）

でも、この様な自体は開発中にあり得ることなので頭の片隅に置いておくと良いでしょう。


##バージョン
• Laravel 5.5 
• PHP 7.1.29 
• MySQL  Ver 5.6.44
• Composer version 2.0.8
• VIM - Vi IMproved 7.4

##2 やりたいこと
ビューを表示するビジネスロジックをコントローラから分離して記述するためにView Composerを使ってControllerに書かないようにする。ViewComposerはPresenterのような役割をしています。この切り分けをすることによってテストもしやすくなり、独立性も上がります。

それでは、早速書き方に移りましょう！　

.
.
.


と、その前にここの例で使うディレクトリの構成を書いておきます


```
ディレクトリ構成 (引用先： https://tsukada.sumito.jp/2019/12/09/laravel-5-5-directory/)

├── app
│   ├── Console
│   ├── Exceptions
│   ├── Http
│   │   ├── Controllers
|   |   |       └──AccountController.php ← ココ
│   │   ├── Kernel.php
│   │   ├── Middleware
|   |   └── ViewComposers
|   |           └── UserComposer.php ← ココ
│   ├── Providers
|   |       └── ViewComposerServiceProvider ← ココ
│   └── User.php
├── artisan
├── bootstrap
├── composer.json
├── composer.lock
├── config 
│   ├── app.php ← ココ
│   ├── auth.php
│   ├── broadcasting.php
│   ├── cache.php
│   ├── database.php
│   ├── filesystems.php
│   ├── mail.php
│   ├── queue.php
│   ├── services.php
│   ├── session.php
│   └── view.php
├── database
├── package.json
├── phpunit.xml
├── public
├── resources
│   ├── assets
│   ├── lang
│   └── views
│   　　　└── account 
|         　　　├── detail1.blade.php ← ココ 
|         　　　└── detail2.blade.php ← ココ
├── routes
│   ├── api.php
│   ├── channels.php
│   ├── console.php
│   └── web.php
├── server.php
├── storage
├── tests
├── vendor
└── webpack.mix.js

```

----------------------
補足：
routes\web.phpで、detail1.blade.phpを'account.detail1'　と　detail2.blade.phpを'account.detail2'と名前指定しています。


##3. view composerのサービスプロパイダーの登録

```PHP:ViewComposerServiceProvider.php 

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View; //FacadesのViewを使用！
use App\Http\ViewComposers\UserComposer; //Composerと紐付けさせるので指定します
class ViewComposerServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
	public function boot()
	{
        /* 説明:
　　　　　　account.* を使うことでaccount.~と指定されたView全てに値を受け渡すことができる。
          ファイルに受け渡しが可能になる！どのComposerと紐づけるかも、指定しないといけません！
        */
		View::composer(['account.*'], UserComposer::class);
	}

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

```


##4. Composerの作成


```PHP:UserComposer.php
<?php

namespace App\Http\ViewComposers;

use Illuminate\Support\Facades\Auth; // 今回は、ログイン者の情報の表示のためFacadesのAuthを使います
use Illuminate\View\View; //Viewインスタンスで値の受け渡しをする際に使います

class UserComposer
{
	public function compose(View $view)
	{
		$view->with('user', Auth::user());
	}
}

```


##5. config\app.phpでview composerのサービスプロパイダーの付け足し


```PHP:config\app.php

<?php

return [

        .
        .
        .
        省略
        .
        .
        .
    'providers' => [

                .
                .
                .
                省略
                .
                .
                .
        /*
         * Application Service Providers...
         */

         //ここにViewComposerServiceProviderを付け足します。
          App\Providers\ViewComposerServiceProvider::class,
    ],
        .
        .
        .
        省略
        .
        .
        .
];

```

##6. AccountControllerの作成

```PHP:AccountController.php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;

final class AccountController extends Controller
{
	public function show1()
	{
		return view('account.detail1'); //->with(~)の付け足し不要！
	}

	public function show2()
	{
		return view('account.detail2'); //->with(~)の付け足し不要！
	}
}

```

##7. viewファイルでUserComposer.phpで定義した変数の呼び出し！

例えば、usersテーブルにメール(email)、名前(name)、電話番号(phone)、住所の情報(address)が入っているとします。

resources/views/account/detail1.blade.phpには、名前と住所の情報を書き込み、
resources/views/account/detail2.blade.phpには、メールと電話番号を書き込みます。


```PHP:detail1.blade.php
@extends('layouts.app')

@section('content')
<div class="container">

<div class="panel panel-default">
<div class="panel-heading">アカウント情報1</div>

<div class="panel-body">
<h4>名前: </h4>
<h3><strong>{{ $user->name }}</strong></h3>
<h4>メールアドレス: </h4>
<h3><strong>{{ $user->address }}</strong></h4>
</div>
</div>
</div>
@endsection

```

```PHP:detail2.blade.php
@extends('layouts.app')

@section('content')
<div class="container">

<div class="panel panel-default">
<div class="panel-heading">アカウント情報2</div>

<div class="panel-body">
<h4>名前: </h4>
<h3><strong>{{ $user->email }}</strong></h3>
<h4>メールアドレス: </h4>
<h3><strong>{{ $user->phone }}</strong></h4>
</div>
</div>
</div>
@endsection


```

と、このようにコントローラーでviewファイル毎に特定の変数の受け渡し処理を書かずにできます！


##終わりに


長くなりましたが、以上となります！お疲れ様でした！
これからも、有益な情報を皆様に発信していこうと思いますので、応援よろしくお願い致します！
<strong>LGTM よろしくお願いします！</strong>



##参考サイト
https://apsdsm.com/post/155429307320/how-do-i-unit-test-a-view-composer-in-laravel
https://stackoverflow.com/questions/41221195/laravel-passing-a-variable-to-multiple-views
https://laravel.com/docs/5.5/views