Bladeテンプレート
イントロダクション
BladeはシンプルながらパワフルなLaravelのテンプレートエンジンです。他の人気のあるPHPテンプレートエンジンとは異なり、ビューの中にPHPを直接記述することを許しています。全BladeビューはPHPへコンパイルされ、変更があるまでキャッシュされます。つまりアプリケーションのオーバーヘッドは基本的に0です。Bladeビューには.blade.php
ファイル拡張子を付け、通常はresources/views
ディレクトリの中に設置します。
テンプレートの継承
レイアウト定義
Bladeを使用する主な利点は、テンプレートの継承とセクションです。初めに簡単な例を見てください。通常ほとんどのアプリケーションでは、数多くのページを同じ全体的なレイアウトの中に表示するので、最初は"master"ページレイアウトを確認しましょう。レイアウトは一つのBladeビューとして、簡単に定義できます。
<!-- resources/views/layouts/app.blade.phpとして保存 -->
<html>
<head>
<title>アプリ名 - @yield('title')</title>
</head>
<body>
@section('sidebar')
ここがメインのサイドバー
@show
<div class="container">
@yield('content')
</div>
</body>
</html>
ご覧の通り、典型的なHTMLマークアップで構成されたファイルです。しかし、@section
や@yield
ディレクティブに注目です。@section
ディレクティブは名前が示す通りにコンテンツのセクションを定義し、一方の@yield
ディレクティブは指定したセションの内容を表示するために使用します。
これでアプリケーションのレイアウトが定義できました。このレイアウトを継承する、子のページを定義しましょう。
レイアウト拡張
子のページを定義するには、「継承」するレイアウトを指定する、Blade
@extends
ディレクティブを使用します。Bladeレイアウトを拡張するビューは、@section
ディレクティブを使用し、レイアウトのセクションに内容を挿入します。前例にあるようにレイアウトでセクションを表示するには@yield
を使用します。
<!-- resources/views/child.blade.phpとして保存 -->
@extends('layouts.app')
@section('title', 'Page Title')
@section('sidebar')
@@parent
<p>ここはメインのサイドバーに追加される</p>
@endsection
@section('content')
<p>ここが本文のコンテンツ</p>
@endsection
この例のsidebar
セクションでは、レイアウトのサイドバーの内容をコンテンツに上書きするのではなく追加するために@@parent
ディレクティブを使用しています。@@parent
ディレクティブはビューをレンダーするときに、レイアウトの内容に置き換わります。
Bladeビューはグローバルなview
ヘルパを使用し、ルートから返すことができます。
Route::get('blade', function () {
return view('child');
});
データ表示
Bladeビューに渡されたデータは、波括弧で変数を囲うことで表示できます。たとえば、次のルートがあるとしましょう。
Route::get('greeting', function () {
return view('welcome', ['name' => 'Samantha']);
});
name
変数の内容を表示しましょう。
Hello, {{ $name }}.
もちろんビューに渡された変数の内容を表示するだけに限られません。PHP関数の結果をechoすることもできます。実際、どんなPHPコードもBladeのecho文の中に書けます。
The current UNIX timestamp is {{ time() }}.
Note: Bladeの
{{ }}
記法はXSS攻撃を防ぐため、自動的にPHPのhtmlentities
関数を通されます。
存在時のデータ表示
変数をechoしたいが、その変数がセットされているかわからない場合もあるでしょう。複雑なPHPコードを使えば可能です。
{{ isset($name) ? $name : 'Default' }}
しかし三項演算子を書く代わりに、Bladeは便利な次の短縮形を提供しており、上記の参考演算子へコンパイルされます。
{{ $name or 'Default' }}
この例の場合、$name
変数が存在すれば値が表示されます。しかし存在していなければDefault
という言葉が表示されます。
エスケープしないデータの表示
デフォルトでブレードの{{ }}
文はXSS攻撃を防ぐために、PHPのhtmlentities
関数を自動的に通されます。しかしデータをエスケープしたくない場合は、以下の構文を使ってください。
Hello, {!! $name !!}.
Note: アプリケーションでユーザの入力内容をechoする場合は注意が必要です。ユーザの入力を表示するときは、常に二重の波括弧の記法でHTMLエンティティにエスケープすべきです。
BladeとJavaScriptフレームワーク
多くのJavaScriptフレームワークでも、与えられた式をブラウザに表示するために波括弧を使っていますので、@
シンボルでBladeレンダリングエンジンに波括弧の展開をしないように指示することが可能です。
<h1>Laravel</h1>
Hello, @{{ name }}.
この例で、@
記号はBladeにより削除されます。しかし、{{ name }}
式はBladeエンジンにより変更されずにそのまま残り、JavaScriptフレームワークによりレンダリングできるようになります。
@verbatim
ディレクティブ
テンプレートの広い箇所でJavaScript変数を表示する場合は、HTMLを@verbatim
ディレクティブで囲めば、各Blade
echo文の先頭に@
記号を付ける必要はなくなります。
@verbatim
<div class="container">
Hello, {{ name }}.
</div>
@endverbatim
制御構文
テンプレートの継承とデータ表示に付け加え、Bladeは条件文やループなどの一般的なPHPの制御構文の便利な短縮形を提供しています。こうした短縮形はPHP制御構文のきれいで簡潔な記述を提供しつつも、対応するPHPの構文とそっくりです。
If文
if
文の構文には、@if
、@elseif
、@else
、@endif
ディレクティブを使用します。これらの使い方はPHPの構文と同じです。
@if (count($records) === 1)
1レコードある!
@elseif (count($records) > 1)
複数レコードある!
@else
レコードがない!
@endif
便利なように、Bladeでは@unlessディレクティブも提供しています。
@unless (Auth::check())
あなたはログインしていません。
@endunless
繰り返し
条件文に加え、BladeはPHPがサポートしている繰り返し構文も提供しています。これらも、対応するPHP構文と使い方は一緒です。
@for ($i = 0; $i < 10; $i++)
現在の値は: {{ $i }}
@endfor
@foreach ($users as $user)
<p>これは {{ $user->id }} ユーザです。</p>
@endforeach
@forelse ($users as $user)
<li>{{ $user->name }}</li>
@empty
<p>ユーザなし</p>
@endforelse
@while (true)
<p>無限ループ中</p>
@endwhile
Tip!! 繰り返し中はループ変数を使い、繰り返しの最初や最後なのかなど、繰り返し情報を取得できます。
繰り返しを使用する場合、ループを終了するか、現在の繰り返しをスキップすることもできます。
@foreach ($users as $user)
@if ($user->type == 1)
@continue
@endif
<li>{{ $user->name }}</li>
@if ($user->number == 5)
@break
@endif
@endforeach
もしくは、ディレクティブに条件を記述して、一行で済ますこともできます。
@foreach ($users as $user)
@continue($user->type == 1)
<li>{{ $user->name }}</li>
@break($user->number == 5)
@endforeach
ループ変数
繰り返し中は、$loop
変数が使用できます。この変数により、現在のループインデックスや繰り返しの最初/最後なのかなど、便利な情報にアクセスできます。
@foreach ($users as $user)
@if ($loop->first)
これは最初の繰り返し
@endif
@if ($loop->last)
これは最後の繰り返し
@endif
<p>これは {{ $user->id }} ユーザです。</p>
@endforeach
ネストした繰り返しでは、親のループの$loop
変数にparent
プロパティを通じアクセスできます。
@foreach ($users as $user)
@foreach ($user->posts as $post)
@if ($loop->parent->first)
これは親のループの最初の繰り返しだ
@endif
@endforeach
@endforeach
$loop
変数は、他にもいろいろと便利なプロパティを持っています。
プロパティ | 説明 |
---|---|
$loop->index |
現在のループのインデックス(初期値0) |
$loop->iteration |
現在の繰り返し数(初期値1) |
$loop->remaining |
繰り返しの残り数 |
$loop->count |
繰り返し中の配列の総アイテム数 |
$loop->first |
ループの最初の繰り返しか |
$loop->last |
ループの最後の繰り返しか |
$loop->depth |
現在のループのネストレベル |
$loop->parent |
ループがネストしている場合、親のループ変数 |
コメント
Bladeでビューにコメントを書くこともできます。HTMLコメントと異なり、Bladeのコメントはアプリケーションから返されるHTMLには含まれません。
{{-- このコメントはレンダー後のHTMLには現れない --}}
サブビューの読み込み
Bladeの@include
ディレクディブを使えば、ビューの中から簡単に他のBladeビューを取り込めます。読み込み元のビューで使用可能な変数は、取り込み先のビューでも利用可能です。
<div>
@include('shared.errors')
<form>
<!-- フォームの内容 -->
</form>
</div>
親のビューの全データ変数が取り込み先のビューに継承されますが、追加のデータも配列で渡すことができます。
@include('view.name', ['some' => 'data'])
Note: Bladeビューの中では
__DIR__
や__FILE__
を使わないでください。キャッシュされたコンパイル済みのビューのパスが返されるからです。
コレクションのレンダービュー
Bladeの@each
ディレクティブを使い、ループとビューの読み込みを組み合わせられます。
@each('view.name', $jobs, 'job')
最初の引数は配列かコレクションの各要素をレンダーするための部分ビューです。第2引数は繰り返し処理する配列かコレクションで、第3引数はビューの中の繰り返し値が代入される変数名です。ですから、たとえばjobs
配列を繰り返す場合なら、部分ビューの中で各ジョブにはjob
変数としてアクセスしたいと通常は考えるでしょう。
現在の繰り返しのキーは、部分ビューの中のkey
変数で参照できます。
@each
ディレクティブには第4引数を渡たせます。この引数は配列が空の場合にレンダーされるビューを指定します。
@each('view.name', $jobs, 'job', 'view.empty')
スタック
Bladeはさらに、他のビューやレイアウトでレンダーできるように、名前付きのスタックへ内容を退避できます。子ビューで必要なJavaScriptを指定する場合に、便利です。
@push('scripts')
<script src="/example.js"></script>
@endpush
必要なだけ何回もスタックをプッシュできます。スタックした内容をレンダーするには、@stack
ディレクティブにスタック名を指定してください。
<head>
<!-- Headの内容 -->
@stack('scripts')
</head>
サービス注入
@inject
ディレクティブはLaravelのサービスコンテナからサービスを取得するために使用します。@inject
の最初の引数はそのサービスを取り込む変数名で、第2引数は依存解決したいクラス/インターフェイス名です。
@inject('metrics', 'App\Services\MetricsService')
<div>
Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
</div>
Blade拡張
Bladeではdirective
メソッドを使い、自分のカスタムディレクティブを定義することができます。Bladeコンパイラがそのカスタムディレクティブを見つけると、そのディレクティブに渡される引数をコールバックへの引数として呼び出します。。
次の例は@datetime($var)
ディレクティブを作成し、渡されるDateTime
インスタンスの$var
をフォーマットします。
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* サービスの初期起動後に登録する
*
* @return void
*/
public function boot()
{
Blade::directive('datetime', function($expression) {
return "<?php echo $expression->format('m/d/Y H:i'); ?>";
});
}
/**
* コンテナへ結合を登録する
*
* @return void
*/
public function register()
{
//
}
}
ご覧の通り、ディレクティブがどんなものであれ、渡された引数にformat
メソッドをチェーンし、呼び出しています。そのため、この例のディレクティブの場合、最終的に生成されるPHPコードは、次のようになります。
<?php echo $var->format('m/d/Y H:i'); ?>
Note: Bladeディレクティブのロジックを更新した後に、Bladeビューのキャッシュを全部削除する必要があります。
view:clear
Artisanコマンドで、キャッシュされているBladeビューを削除できます。