このリポジトリはPHP Webアプリフレームワークである、LaravelのLTSバージョンである5.5の公式英文ドキュメントを日本語へ翻訳しています。
This project is maintained by okinaka
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
ディレクティブはビューをレンダーするときに、レイアウトの内容に置き換わります。
{tip} 直前の例とは異なり、この
sidebar
セクションは@show
の代わりに@endsection
で終わっています。@endsection
ディレクティブはセクションを定義するだけに対し、@show
は定義しつつ、そのセクションを即時にその場所に取り込みます。
Bladeビューはグローバルなview
ヘルパを使用し、ルートから返すことができます。
Route::get('blade', function () {
return view('child');
});
コンポーネントとスロットは、セクションとレイアウトと似た利便を提供します。しかし、コンポーネントとスロットのメンタルモデルのほうが簡単に理解できることに気づくはずです。最初に、アプリケーション全体で再利用する、”alert”コンポーネントをイメージしてください。
<!-- /resources/views/alert.blade.php -->
<div class="alert alert-danger">
</div>
``変数は、このコンポーネントへ注入しようとする内容を含んでいます。では、このコンポーネントを構築するため、@component
Bladeディレクティブを使いましょう。
@component('alert')
<strong>Whoops!</strong> Something went wrong!
@endcomponent
一つのコンポーネントに対し、複数のスロットを定義するのも、役立つことがあるでしょう。”title”を注入できるようにalertコンポーネントを改造してみましょう。名前付きスロットは、名前に一致する変数をただ”echo”します。
<!-- /resources/views/alert.blade.php -->
<div class="alert alert-danger">
<div class="alert-title"></div>
</div>
これで、@slot
ディレクティブを使い、名前付きスロットへ内容を注入できます。@slot
ディレクティブ範囲外の全内容は、$slot
変数の中のコンポーネントへ渡されます。
@component('alert')
@slot('title')
Forbidden
@endslot
You are not allowed to access this resource!
@endcomponent
場合により、コンポーネントへ追加のデータを渡す必要が起きます。そのため、@component
ディレクティブの第2引数で、データの配列が渡せます。全データはテンプレート中で変数として利用できます。
@component('alert', ['foo' => 'bar'])
...
@endcomponent
Bladeビューに渡されたデータは、波括弧で変数を囲うことで表示できます。たとえば、次のルートがあるとしましょう。
Route::get('greeting', function () {
return view('welcome', ['name' => 'Samantha']);
});
name
変数の内容を表示しましょう。
Hello, .
もちろんビューに渡された変数の内容を表示するだけに限られません。PHP関数の結果をechoすることもできます。実際、どんなPHPコードもBladeのecho文の中に書けます。
The current UNIX timestamp is .
{tip} Bladeの``記法はXSS攻撃を防ぐため、自動的にPHPの
htmlspecialchars
関数を通されます。
デフォルトでブレードの``文はXSS攻撃を防ぐために、PHPのhtmlspecialchars
関数を自動的に通されます。しかしデータをエスケープしたくない場合は、以下の構文を使ってください。
Hello, {!! $name !!}.
{note} アプリケーションでユーザーの入力内容をechoする場合は注意が必要です。ユーザーの入力を表示するときは、常に二重の波括弧の記法でHTMLエンティティにエスケープすべきです。
JavaScriptの変数を初期化するために、配列をビューに渡してJSONとして描画することができます。
<script>
var app = <?php echo json_encode($array); ?>;
</script>
その際、json_encode
を使う代わりに、@json
ディレクティブを使うことができます。
<script>
var app = @json($array);
</script>
多くのJavaScriptフレームワークでも、与えられた式をブラウザに表示するために波括弧を使っていますので、@
シンボルでBladeレンダリングエンジンに波括弧の展開をしないように指示することが可能です。
<h1>Laravel</h1>
Hello, @.
この例で、@
記号はBladeにより削除されます。しかし、``式はBladeエンジンにより変更されずにそのまま残り、JavaScriptフレームワークによりレンダリングできるようになります。
@verbatim
ディレクティブテンプレートの広い箇所でJavaScript変数を表示する場合は、HTMLを@verbatim
ディレクティブで囲めば、各Blade echo文の先頭に@
記号を付ける必要はなくなります。
@verbatim
<div class="container">
Hello, .
</div>
@endverbatim
テンプレートの継承とデータ表示に付け加え、Bladeは条件文やループなどの一般的なPHPの制御構文の便利な短縮記述方法を提供しています。こうした短縮形は、PHP制御構文の美しく簡潔な記述を提供しつつも、対応するPHPの構文と似せています。
if
文の構文には、@if
、@elseif
、@else
、@endif
ディレクティブを使用します。これらの使い方はPHPの構文と同じです。
@if (count($records) === 1)
1レコードある!
@elseif (count($records) > 1)
複数レコードある!
@else
レコードがない!
@endif
便利な@unlessディレクティブも提供しています。
@unless (Auth::check())
あなたはログインしていません。
@endunless
さらに、既に説明したように@isset
と@empty
ディレクティブも、同名のPHP関数の便利なショートカットとして使用できます。
@isset($records)
// $recordsは定義済みでnullでない
@endisset
@empty($records)
// $recordsが「空」だ
@endempty
@auth
と@guest
ディレクティブは、現在のユーザーが認証されているか、もしくはゲストであるかを簡単に判定するために使用します。
@auth
// ユーザーは認証済み
@endauth
@guest
// ユーザーは認証されていない
@endguest
必要であれば、@auth
と@guest
ディレクティブ使用時に、確認すべき認証ガードを指定できます。
@auth('admin')
// ユーザーは認証済み
@endauth
@guest('admin')
// ユーザーは認証されていない
@endguest
@switch
、@case
、@break
、@default
、@endswitch
ディレクティブを使用し、switch文を構成できます。
@switch($i)
@case(1)
最初のケース
@break
@case(2)
2番めのケース
@break
@default
デフォルトのケース
@endswitch
条件文に加え、BladeはPHPがサポートしている繰り返し構文も提供しています。これらも、対応するPHP構文と使い方は一緒です。
@for ($i = 0; $i < 10; $i++)
現在の値は:
@endfor
@foreach ($users as $user)
<p>これは ユーザーです。</p>
@endforeach
@forelse ($users as $user)
<li></li>
@empty
<p>ユーザーなし</p>
@endforelse
@while (true)
<p>無限ループ中</p>
@endwhile
{tip} 繰り返し中はループ変数を使い、繰り返しの最初や最後なのかなど、繰り返し情報を取得できます。
繰り返しを使用する場合、ループを終了するか、現在の繰り返しをスキップすることもできます。
@foreach ($users as $user)
@if ($user->type == 1)
@continue
@endif
<li></li>
@if ($user->number == 5)
@break
@endif
@endforeach
もしくは、ディレクティブに条件を記述して、一行で済ますこともできます。
@foreach ($users as $user)
@continue($user->type == 1)
<li></li>
@break($user->number == 5)
@endforeach
繰り返し中は、$loop
変数が使用できます。この変数により、現在のループインデックスや繰り返しの最初/最後なのかなど、便利な情報にアクセスできます。
@foreach ($users as $user)
@if ($loop->first)
これは最初の繰り返し
@endif
@if ($loop->last)
これは最後の繰り返し
@endif
<p>これは ユーザーです。</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には含まれません。
PHPコードをビューへ埋め込むと便利な場合もあります。Bladeの@php
ディレクティブを使えば、テンプレートの中でプレーンなPHPブロックを実行できます。
@php
//
@endphp
{tip} Bladeはこの機能を提供していますが、数多く使用しているのであれば、それはテンプレートへ多すぎるロジックを埋め込んでいるサインです。
Bladeの@include
ディレクディブを使えば、ビューの中から簡単に他のBladeビューを取り込めます。読み込み元のビューで使用可能な変数は、取り込み先のビューでも利用可能です。
<div>
@include('shared.errors')
<form>
<!-- フォームの内容 -->
</form>
</div>
親のビューの全データ変数が取り込み先のビューに継承されますが、追加のデータも配列で渡すことができます。
@include('view.name', ['some' => 'data'])
もちろん、存在しないビューを@include
すれば、Laravelはエラーを投げます。存在しているかどうかわからないビューを取り込みたい場合は、@includeIf
ディレクティブを使います。
@includeIf('view.name', ['some' => 'data'])
指定した論理条件にもとづいて@include
したい場合は、@includeWhen
ディレクティブを使用します。
@includeWhen($boolean, 'view.name', ['some' => 'data'])
指定するビューの配列から、最初に存在するビューを読み込むには、includeFirst
ディレクティブを使用します。
@includeFirst(['custom.admin', 'admin'], ['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')
{note}
@each
を使ってレンダされるビューは、親のビューから変数を継承しません。子ビューで親ビューの変数が必要な場合は、代わりに@foreach
と@include
を使用してください。
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: .
</div>
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ビューを削除できます。
シンプルなカスタム条件文を定義する時、必要以上にカスタムディレクティブのプログラミングが複雑になってしまうことが、時々起きます。そのため、Bladeはクロージャを使用し、カスタム条件ディレクティブを素早く定義できるように、Blade::if
メソッドを提供しています。例として、現在のアプリケーション環境をチェックするカスタム条件を定義してみましょう。AppServiceProvider
のboot
メソッドで行います。
use Illuminate\Support\Facades\Blade;
/**
* サービスの初期処理後に実行
*
* @return void
*/
public function boot()
{
Blade::if('env', function ($environment) {
return app()->environment($environment);
});
}
カスタム条件を定義したら、テンプレートの中で簡単に利用できます。
@env('local')
// アプリケーションはlocal環境
@elseenv('testing')
// アプリケーションはtesting環境
@else
// アプリケーションは、local環境でもtesting環境でもない
@endenv