[Laravel] ViewComposer でコントローラをすっきりさせる
コードの保守性を高めるためのちょっとしたテクニック。
ViewComposer ってなに?
View に変数を結合するためのしくみです。
普通ならコントローラの各メソッドで view()->with(compact('user'))
のようにして渡すところを、別の場所で渡すことができます。
たとえば、以下のように変数を渡す処理をコントローラから削除できます。
public function index()
{
$users = User::all();
$count = $users->count();
return view('user.index')->with(compact('users', 'count'));
}
// ViewComposer を使って $count を別の場所で定義した
public function index()
{
$users = User::all();
return view('user.index')->with(compact('users'));
}
2 つ目のコードには $count
が定義されていませんが、ViewCompoesr によって定義されているので、user.index
のなかでちゃんと使うことができます。
ちなみに、結合処理が実行される (View と変数が結合される) のは、View が render されるときです。
何がうれしいの?
メリットはおもに 2 つ。
1 つはコントローラがすっきりすること。
たとえば、次のコードでは $count
が複数箇所に現れていて冗長ですが、
public function index()
{
$users = User::all()
$count = $users->count();
return view('user.index')->with(compact('users', 'count'));
}
public function show(User $user)
{
$count = User::all()->count();
return view('user.show')->with(compact('user', 'count'));
}
$count
を渡す処理を ViewComposer で書けば、以下のようにすっきりします。
public function index()
{
return view('user.index')->with(['users' => User::all()]);
}
public function show(User $user)
{
return view('user.show')->with(compact('user'));
}
もう 1 つは、1 箇所にまとまっていて修正しやすいこと。
ViewComposer は複数箇所に定義されている同じ変数を 1 箇所にまとめることができます。
先の例では $count
の出現箇所はたった 2 箇所でしたが、これが複数のコントローラをまたいで数 10 箇所にもなったら、変更するのが非常に大変です。
それに、変更漏れがあればバグを引き起こしかねません。
その点、ViewComposer で View と変数の結合を一括管理しておけば、その心配はなくなります。
どうやって作るの?
1. ServiceProvider を作る
php artisan make:provider ViewServiceProvider
App\Providers\ViewServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class ViewServiceProvider extends ServiceProvider
{
public function boot()
{
//
}
public function register()
{
//
}
}
config への追加も忘れずに。
config/app.php
'providers' => [
...
+ App\Providers\ViewServiceProvider::class,
],
2. Composer を作る
特にコマンドは用意されていないので、手動でファイルを作ります。
App\Http\View\Composers\UserComposer.php
<?php
namespace App\Http\View\Composers;
use App\User;
use Illuminate\View\View;
class UserComposer
{
protected $users;
public function __construct()
{
$this->users = User::all();
}
public function compose(View $view)
{
$view->with('count', $this->users->count());
}
}
3. 表示してみる
app\Providers\ViewServiceProvider.php
public function boot()
{
View::composer(
'welcome', 'App\Http\View\Composers\UserComposer'
);
}
app\resources\views\welcome.blade.php
- <title>Laravel</title>
+ <title>Laravel {{ $count }}</title>
ここまでくれば、welcome ページで $count
が使えるはず。
resources\views\user\index.blade.php
で使いたいときは、以下のようにします。
public function boot()
{
View::composer(
'user.index', 'App\Http\View\Composers\UserComposer'
);
}
resources\views\user
配下のすべてのビューに適用したいときは、以下のように書くしかなさそうです。
public function boot()
{
View::composer(
['user.index', 'user.create', 'user.show', 'user.edit'],
'App\Http\View\Composers\UserComposer'
);
}
実際には、ヘッダやサイドメニューで使う変数を ViewComposer で定義することが多いので、
header.blade.php
や sidemenu.blade.php
などに対して変数を結合することになると思います。
ちなみに、その場合は変数の結合を定義した blade 内でしか変数を参照できないことに注意が必要です。
つまり、header.blade.php
に結合した変数を、header.blade.php
をインポートするような別ファイルのなかで使うことはできないということです。