Bladeテンプレート¶
- はじめに
- データの表示
- Bladeディレクティブ
- コンポーネント
- 匿名コンポーネント
- レイアウトの構築
- フォーム
- スタック
- サービスインジェクション
- インラインBladeテンプレートのレンダリング
- Bladeフラグメントのレンダリング
- Bladeの拡張
はじめに¶
Bladeは、Laravelに含まれるシンプルで強力なテンプレートエンジンです。他のPHPテンプレートエンジンとは異なり、Bladeはテンプレート内でプレーンなPHPコードを使用することを制限しません。実際、すべてのBladeテンプレートはプレーンなPHPコードにコンパイルされ、変更されるまでキャッシュされるため、Bladeはアプリケーションに実質的にゼロのオーバーヘッドを追加します。Bladeテンプレートファイルは.blade.php
ファイル拡張子を使用し、通常はresources/views
ディレクトリに保存されます。
Bladeビューは、グローバルなview
ヘルパーを使用してルートまたはコントローラから返されることがあります。もちろん、ビューのドキュメントで説明されているように、view
ヘルパーの2番目の引数を使用してBladeビューにデータを渡すことができます。
Route::get('/', function () {
return view('greeting', ['name' => 'Finn']);
});
LivewireでBladeを強化する¶
Bladeテンプレートを次のレベルに引き上げ、動的なインターフェースを簡単に構築したいですか?Laravel Livewireをチェックしてください。Livewireを使用すると、ReactやVueのようなフロントエンドフレームワークでのみ可能な動的な機能を持つBladeコンポーネントを書くことができ、多くのJavaScriptフレームワークの複雑さ、クライアントサイドレンダリング、ビルドステップを回避しながら、現代のリアクティブフロントエンドを構築するための素晴らしいアプローチを提供します。
データの表示¶
変数を波括弧で囲むことで、Bladeビューに渡されたデータを表示できます。たとえば、次のルートがあるとします。
Route::get('/', function () {
return view('welcome', ['name' => 'Samantha']);
});
name
変数の内容を次のように表示できます。
Note
Bladeの{{ }}
エコー文は、XSS攻撃を防ぐために、自動的にPHPのhtmlspecialchars
関数を通過します。
ビューに渡された変数の内容を表示することに限定されません。PHP関数の結果もエコーできます。実際、Bladeエコー文の中に任意のPHPコードを配置できます。
HTMLエンティティのエンコーディング¶
デフォルトでは、Blade(およびLaravelのe
関数)はHTMLエンティティを二重にエンコードします。二重エンコードを無効にしたい場合は、AppServiceProvider
のboot
メソッドからBlade::withoutDoubleEncoding
メソッドを呼び出します。
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* アプリケーションサービスの初期化処理
*/
public function boot(): void
{
Blade::withoutDoubleEncoding();
}
}
エスケープされていないデータの表示¶
デフォルトでは、Bladeの{{ }}
文は自動的にPHPのhtmlspecialchars
関数を通過してXSS攻撃を防ぎます。データをエスケープしたくない場合は、次の構文を使用できます。
Warning
アプリケーションのユーザーによって提供されたコンテンツを表示する場合は、十分に注意してください。通常、ユーザー提供のデータを表示する場合は、エスケープされた二重波括弧構文を使用してXSS攻撃を防ぐ必要があります。
BladeとJavaScriptフレームワーク¶
多くのJavaScriptフレームワークも、ブラウザに表示されるべき式を示すために「波括弧」を使用するため、@
記号を使用してBladeレンダリングエンジンに式をそのままにしておくように指示できます。例えば:
この例では、@
記号はBladeによって削除されますが、{{ name }}
式はBladeエンジンによってそのままにされ、JavaScriptフレームワークによってレンダリングされます。
@
記号は、Bladeディレクティブをエスケープするためにも使用できます。
JSONのレンダリング¶
JavaScript変数を初期化するために配列をビューに渡してJSONとしてレンダリングすることがあります。例えば:
しかし、手動でjson_encode
を呼び出す代わりに、Illuminate\Support\Js::from
メソッドディレクティブを使用できます。from
メソッドは、PHPのjson_encode
関数と同じ引数を受け取りますが、結果のJSONがHTMLクォート内に正しくエスケープされることを保証します。from
メソッドは、指定されたオブジェクトまたは配列を有効なJavaScriptオブジェクトに変換するJSON.parse
JavaScript文を返します。
最新バージョンのLaravelアプリケーションスケルトンには、Bladeテンプレート内でこの機能に簡単にアクセスできるJs
ファサードが含まれています。
Warning
Js::from
メソッドは、既存の変数をJSONとしてレンダリングするためにのみ使用してください。Bladeテンプレートは正規表現に基づいており、複雑な式をディレクティブに渡そうとすると、予期しない失敗が発生する可能性があります。
@verbatim
ディレクティブ¶
テンプレートの大部分でJavaScript変数を表示する場合、HTMLを@verbatim
ディレクティブでラップして、各Bladeエコー文に@
記号を付ける必要をなくすことができます。
Bladeディレクティブ¶
テンプレートの継承やデータ表示に加え、Bladeは条件文やループなどのPHPの制御構造を簡潔に記述できるショートカットを提供します。これらのショートカットは、PHP制御構造を非常にクリーンで簡潔な方法で操作するのに役立ち、それらのPHPの対応物にも馴染みがあります。
If文¶
@if
、@elseif
、@else
、@endif
ディレクティブを使用してif
文を構築できます。これらのディレクティブは、対応するPHPのものと同じように機能します。
@if (count($records) === 1)
I have one record!
@elseif (count($records) > 1)
I have multiple records!
@else
I don't have any records!
@endif
利便性のために、Bladeは@unless
ディレクティブも提供します。
条件ディレクティブに加えて、@isset
と@empty
ディレクティブを、それぞれのPHP関数の便利なショートカットとして使用できます。
@isset($records)
// $recordsが定義されており、nullでない場合...
@endisset
@empty($records)
// $recordsが「空」の場合...
@endempty
認証ディレクティブ¶
@auth
と@guest
ディレクティブを使用して、現在のユーザーが認証されているか、ゲストであるかをすばやく判断できます。
必要に応じて、@auth
と@guest
ディレクティブを使用する際にチェックする認証ガードを指定できます。
環境ディレクティブ¶
@production
ディレクティブを使用して、アプリケーションが本番環境で実行されているかどうかを確認できます。
または、@env
ディレクティブを使用して、アプリケーションが特定の環境で実行されているかどうかを判断することもできます:
@env('staging')
// アプリケーションは "staging" で実行中...
@endenv
@env(['staging', 'production'])
// アプリケーションは "staging" または "production" で実行中...
@endenv
セクションディレクティブ¶
@hasSection
ディレクティブを使用して、テンプレート継承セクションにコンテンツがあるかどうかを判断できます:
@hasSection('navigation')
<div class="pull-right">
@yield('navigation')
</div>
<div class="clearfix"></div>
@endif
セクションにコンテンツがないかどうかを判断するには、sectionMissing
ディレクティブを使用できます:
セッションディレクティブ¶
@session
ディレクティブは、セッションの値が存在するかどうかを判断するために使用できます。セッションの値が存在する場合、@session
と@endsession
ディレクティブ内のテンプレートコンテンツが評価されます。@session
ディレクティブのコンテンツ内で、セッションの値を表示するために$value
変数をエコーすることができます:
Switch文¶
Switch文は、@switch
、@case
、@break
、@default
、@endswitch
ディレクティブを使用して構築できます:
ループ¶
条件文に加えて、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
Note
foreach
ループを反復処理する際、ループ変数を使用して、ループに関する貴重な情報(例えば、最初または最後の反復処理であるかどうか)を取得できます。
ループを使用する際、@continue
と@break
ディレクティブを使用して、現在の反復処理をスキップしたり、ループを終了したりすることもできます:
@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
ループ変数¶
foreach
ループを反復処理する際、ループ内で$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->even |
これが偶数の反復処理であるかどうか。 |
$loop->odd |
これが奇数の反復処理であるかどうか。 |
$loop->depth |
現在のループのネストレベル。 |
$loop->parent |
ネストされたループ内にいる場合、親のループ変数。 |
条件付きクラスとスタイル¶
@class
ディレクティブは、条件付きでCSSクラス文字列をコンパイルします。このディレクティブは、クラスの配列を受け取ります。配列のキーには追加したいクラスを含み、値はブール式です。配列要素が数値キーを持つ場合、レンダリングされたクラスリストに常に含まれます:
@php
$isActive = false;
$hasError = true;
@endphp
<span @class([
'p-4',
'font-bold' => $isActive,
'text-gray-500' => ! $isActive,
'bg-red' => $hasError,
])></span>
<span class="p-4 text-gray-500 bg-red"></span>
同様に、@style
ディレクティブを使用して、HTML要素に条件付きでインラインCSSスタイルを追加できます:
@php
$isActive = true;
@endphp
<span @style([
'background-color: red',
'font-weight: bold' => $isActive,
])></span>
<span style="background-color: red; font-weight: bold;"></span>
追加の属性¶
便宜上、@checked
ディレクティブを使用して、指定されたHTMLチェックボックス入力が「チェック済み」であるかどうかを簡単に示すことができます。このディレクティブは、提供された条件がtrue
と評価された場合にchecked
を出力します:
同様に、@selected
ディレクティブを使用して、指定された選択オプションが「選択済み」であるかどうかを示すことができます:
<select name="version">
@foreach ($product->versions as $version)
<option value="{{ $version }}" @selected(old('version') == $version)>
{{ $version }}
</option>
@endforeach
</select>
さらに、@disabled
ディレクティブを使用して、指定された要素が「無効」であるかどうかを示すことができます:
さらに、@readonly
ディレクティブを使用して、指定された要素が「読み取り専用」であるかどうかを示すことができます:
さらに、@required
ディレクティブを使用して、指定された要素が「必須」であるかどうかを示すことができます:
サブビューのインクルード¶
Note
@include
ディレクティブを自由に使用できますが、Bladeのコンポーネントは同様の機能を提供し、データと属性のバインディングなど、@include
ディレクティブよりもいくつかの利点があります。
Bladeの@include
ディレクティブを使用すると、別のビュー内にBladeビューをインクルードできます。親ビューで使用できるすべての変数は、インクルードされたビューでも利用できます:
インクルードされたビューは、親ビューで利用可能なすべてのデータを継承しますが、インクルードされたビューで利用可能にする追加のデータの配列を渡すこともできます:
存在しないビューを@include
しようとすると、Laravelはエラーをスローします。存在するかどうかわからないビューをインクルードしたい場合は、@includeIf
ディレクティブを使用する必要があります:
指定されたブール式がtrue
またはfalse
と評価された場合にビューをインクルードしたい場合は、@includeWhen
と@includeUnless
ディレクティブを使用できます:
@includeWhen($boolean, 'view.name', ['status' => 'complete'])
@includeUnless($boolean, 'view.name', ['status' => 'complete'])
指定されたビューの配列から最初に存在するビューをインクルードするには、includeFirst
ディレクティブを使用できます:
Warning
Bladeビューで__DIR__
と__FILE__
定数を使用することは避けるべきです。キャッシュされたコンパイル済みビューの場所を参照するためです。
コレクションのビューのレンダリング¶
Bladeの@each
ディレクティブを使用して、ループとインクルードを1行にまとめることができます:
@each
ディレクティブの最初の引数は、配列またはコレクションの各要素に対してレンダリングするビューです。2番目の引数は、反復処理したい配列またはコレクションで、3番目の引数は、現在の反復処理内でビューに割り当てられる変数名です。たとえば、jobs
配列を反復処理する場合、通常は各ジョブにjob
変数を使ってアクセスできます。現在の反復処理の配列キーは、ビュー内でkey
変数として利用可能です。
@each
ディレクティブには、4番目の引数を渡すこともできます。この引数は、指定された配列が空の場合にレンダリングされるビューを決定します。
Warning
@each
を介してレンダリングされるビューは、親ビューの変数を継承しません。子ビューがこれらの変数を必要とする場合は、代わりに@foreach
と@include
ディレクティブを使用する必要があります。
@once
ディレクティブ¶
@once
ディレクティブを使用すると、レンダリングサイクルごとに1回だけ評価されるテンプレートの一部を定義できます。これは、stacksを使用して特定のJavaScriptをページのヘッダーにプッシュする場合に便利です。例えば、ループ内で特定のコンポーネントをレンダリングしている場合、コンポーネントが最初にレンダリングされたときにのみJavaScriptをヘッダーにプッシュしたい場合があります。
@once
ディレクティブは、@push
や@prepend
ディレクティブと組み合わせてよく使用されるため、@pushOnce
と@prependOnce
ディレクティブも利用できます。
Raw PHP¶
場合によっては、ビューにPHPコードを埋め込むことが便利なことがあります。Bladeの@php
ディレクティブを使用して、テンプレート内でプレーンなPHPブロックを実行できます。
また、クラスをインポートするためにPHPを使用するだけであれば、@use
ディレクティブを使用できます。
@use
ディレクティブには、インポートされたクラスにエイリアスを付けるための2番目の引数を指定できます。
コメント¶
Bladeでは、ビューにコメントを定義することもできます。ただし、HTMLコメントとは異なり、Bladeコメントはアプリケーションによって返されるHTMLには含まれません。
コンポーネント¶
コンポーネントとスロットは、セクション、レイアウト、インクルードと同様の利点を提供しますが、コンポーネントとスロットのメンタルモデルは理解しやすいかもしれません。コンポーネントを書く方法には、クラスベースのコンポーネントと匿名コンポーネントの2つがあります。
クラスベースのコンポーネントを作成するには、make:component
Artisanコマンドを使用できます。コンポーネントの使用方法を説明するために、シンプルなAlert
コンポーネントを作成します。make:component
コマンドは、コンポーネントをapp/View/Components
ディレクトリに配置します。
make:component
コマンドは、コンポーネントのビューテンプレートも作成します。ビューはresources/views/components
ディレクトリに配置されます。自分のアプリケーション用のコンポーネントを書く場合、コンポーネントはapp/View/Components
ディレクトリとresources/views/components
ディレクトリ内で自動的に検出されるため、通常はコンポーネントの登録を追加する必要はありません。
サブディレクトリ内にコンポーネントを作成することもできます。
上記のコマンドは、app/View/Components/Forms
ディレクトリにInput
コンポーネントを作成し、ビューはresources/views/components/forms
ディレクトリに配置されます。
クラスを持たない匿名コンポーネント(Bladeテンプレートのみを持つコンポーネント)を作成したい場合は、make:component
コマンドを呼び出す際に--view
フラグを使用できます。
上記のコマンドは、resources/views/components/forms/input.blade.php
にBladeファイルを作成します。これは、<x-forms.input />
を介してコンポーネントとしてレンダリングできます。
パッケージコンポーネントの手動登録¶
自分のアプリケーション用のコンポーネントを書く場合、コンポーネントはapp/View/Components
ディレクトリとresources/views/components
ディレクトリ内で自動的に検出されます。
ただし、Bladeコンポーネントを利用するパッケージを構築している場合は、コンポーネントクラスとそのHTMLタグエイリアスを手動で登録する必要があります。通常、コンポーネントはパッケージのサービスプロバイダのboot
メソッドで登録する必要があります。
use Illuminate\Support\Facades\Blade;
/**
* パッケージのサービスを初期化する
*/
public function boot(): void
{
Blade::component('package-alert', Alert::class);
}
コンポーネントが登録されると、タグエイリアスを使ってレンダリングできます。
または、componentNamespace
メソッドを使用して、規約に従ってコンポーネントクラスを自動ロードすることもできます。例えば、Nightshade
パッケージには、Package\Views\Components
名前空間内にCalendar
とColorPicker
コンポーネントがあるかもしれません。
use Illuminate\Support\Facades\Blade;
/**
* パッケージのサービスを初期化する
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}
これにより、ベンダー名前空間を使用してパッケージコンポーネントをpackage-name::
構文で使用できます。
Bladeは、コンポーネント名をパスカルケースにして、このコンポーネントにリンクされたクラスを自動的に検出します。サブディレクトリも「ドット」記法でサポートされています。
コンポーネントのレンダリング¶
コンポーネントを表示するには、Bladeテンプレートの1つでBladeコンポーネントタグを使用できます。Bladeコンポーネントタグは、文字列x-
で始まり、コンポーネントクラスのケバブケース名が続きます。
コンポーネントクラスがapp/View/Components
ディレクトリ内でより深くネストされている場合は、.
文字を使用してディレクトリのネストを示すことができます。例えば、コンポーネントがapp/View/Components/Inputs/Button.php
にあると仮定すると、次のようにレンダリングできます。
コンポーネントを条件付きでレンダリングしたい場合は、コンポーネントクラスにshouldRender
メソッドを定義できます。shouldRender
メソッドがfalse
を返す場合、コンポーネントはレンダリングされません。
use Illuminate\Support\Str;
/**
* コンポーネントをレンダリングするかどうか
*/
public function shouldRender(): bool
{
return Str::length($this->message) > 0;
}
コンポーネントへのデータの受け渡し¶
HTML属性を使用してBladeコンポーネントにデータを渡すことができます。ハードコードされたプリミティブ値は、単純なHTML属性文字列を使用してコンポーネントに渡すことができます。PHP式と変数は、:
文字をプレフィックスとして使用する属性を介してコンポーネントに渡す必要があります。
コンポーネントのすべてのデータ属性をクラスコンストラクタで定義する必要があります。コンポーネントのすべてのパブリックプロパティは、コンポーネントのビューで自動的に利用可能になります。コンポーネントのrender
メソッドからビューにデータを渡す必要はありません。
<?php
namespace App\View\Components;
use Illuminate\View\Component;
use Illuminate\View\View;
class Alert extends Component
{
/**
* コンポーネントインスタンスを作成する
*/
public function __construct(
public string $type,
public string $message,
) {}
/**
* コンポーネントを表すビュー/コンテンツを取得する
*/
public function render(): View
{
return view('components.alert');
}
}
コンポーネントがレンダリングされると、コンポーネントのパブリック変数の内容を変数名でエコーすることで表示できます。
ケーシング¶
コンポーネントコンストラクタの引数はcamelCase
で指定する必要がありますが、HTML属性で引数名を参照する場合はkebab-case
を使用する必要があります。例えば、次のコンポーネントコンストラクタがあるとします。
/**
* コンポーネントインスタンスを作成する
*/
public function __construct(
public string $alertType,
) {}
$alertType
引数は、次のようにコンポーネントに提供できます。
短縮属性構文¶
コンポーネントに属性を渡す際に、「短縮属性」構文を使用することもできます。これは、属性名が対応する変数名と一致する場合に便利です。
{{-- 短縮属性構文... --}}
<x-profile :$userId :$name />
{{-- これは以下と同等です... --}}
<x-profile :user-id="$userId" :name="$name" />
属性レンダリングのエスケープ¶
Alpine.jsなどの一部のJavaScriptフレームワークもコロンプレフィックス付きの属性を使用するため、属性がPHP式でないことをBladeに通知するために、ダブルコロン(::
)プレフィックスを使用できます。例えば、次のコンポーネントがあるとします。
Bladeによって次のHTMLがレンダリングされます。
コンポーネントメソッド¶
コンポーネントテンプレートで利用可能なパブリック変数に加えて、コンポーネントの任意のパブリックメソッドを実行できます。例えば、isSelected
メソッドを持つコンポーネントがあるとします。
/**
* 指定されたオプションが現在選択されているオプションであるかどうかを判断する
*/
public function isSelected(string $option): bool
{
return $option === $this->selected;
}
このメソッドは、メソッド名に一致する変数を呼び出すことで、コンポーネントテンプレートから実行できます。
<option {{ $isSelected($value) ? 'selected="selected"' : '' }} value="{{ $value }}">
{{ $label }}
</option>
コンポーネントクラス内での属性とスロットへのアクセス¶
Bladeコンポーネントでは、コンポーネント名、属性、スロットにクラスのレンダリングメソッド内からアクセスすることもできます。ただし、このデータにアクセスするには、コンポーネントの render
メソッドからクロージャを返す必要があります。
use Closure;
/**
* コンポーネントを表すビュー/コンテンツを取得する
*/
public function render(): Closure
{
return function () {
return '<div {{ $attributes }}>コンポーネントのコンテンツ</div>';
};
}
コンポーネントの render
メソッドから返されるクロージャは、唯一の引数として $data
配列を受け取ることもできます。この配列には、コンポーネントに関する情報を提供するいくつかの要素が含まれます。
return function (array $data) {
// $data['componentName'];
// $data['attributes'];
// $data['slot'];
return '<div {{ $attributes }}>コンポーネントのコンテンツ</div>';
}
Warning
$data
配列の要素を render
メソッドから返される Blade 文字列に直接埋め込むべきではありません。そうすると、悪意のある属性の内容を介してリモートコード実行が可能になる可能性があります。
componentName
は、x-
プレフィックスの後に使用される HTML タグの名前と同じです。したがって、<x-alert />
の componentName
は alert
になります。attributes
要素には、HTML タグに存在したすべての属性が含まれます。slot
要素は、コンポーネントのスロットの内容を持つ Illuminate\Support\HtmlString
インスタンスです。
クロージャは文字列を返す必要があります。返された文字列が既存のビューに対応する場合、そのビューがレンダリングされます。それ以外の場合、返された文字列はインライン Blade ビューとして評価されます。
追加の依存関係¶
コンポーネントが Laravel の サービスコンテナ からの依存関係を必要とする場合、コンポーネントのデータ属性の前にそれらをリストすることができ、コンテナによって自動的に注入されます。
use App\Services\AlertCreator;
/**
* コンポーネントインスタンスを作成する
*/
public function __construct(
public AlertCreator $creator,
public string $type,
public string $message,
) {}
属性/メソッドの非表示¶
コンポーネントテンプレートに変数として公開されることを防ぐために、いくつかのパブリックメソッドやプロパティを非表示にしたい場合は、コンポーネントに $except
配列プロパティを追加することができます。
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class Alert extends Component
{
/**
* コンポーネントテンプレートに公開すべきでないプロパティ/メソッド
*
* @var array
*/
protected $except = ['type'];
/**
* コンポーネントインスタンスを作成する
*/
public function __construct(
public string $type,
) {}
}
コンポーネント属性¶
すでにコンポーネントにデータ属性を渡す方法を見てきましたが、コンポーネントが機能するために必要なデータの一部ではない追加の HTML 属性(例えば class
)を指定する必要がある場合があります。通常、これらの追加属性をコンポーネントテンプレートのルート要素に渡したいと考えます。例えば、alert
コンポーネントを次のようにレンダリングしたいとします。
コンポーネントのコンストラクタの一部ではないすべての属性は、自動的にコンポーネントの「属性バッグ」に追加されます。この属性バッグは、$attributes
変数を介してコンポーネントに自動的に提供されます。この変数をエコーすることで、コンポーネント内のすべての属性をレンダリングできます。
Warning
コンポーネントタグ内で @env
などのディレクティブを使用することは現在サポートされていません。例えば、<x-alert :live="@env('production')"/>
はコンパイルされません。
デフォルト/マージされた属性¶
属性にデフォルト値を指定したり、コンポーネントの一部の属性に追加の値をマージしたりする必要がある場合があります。これを行うには、属性バッグの merge
メソッドを使用できます。このメソッドは、コンポーネントに常に適用される一連のデフォルト CSS クラスを定義するのに特に便利です。
このコンポーネントが次のように使用されると仮定します。
コンポーネントの最終的なレンダリングされた HTML は次のようになります。
条件付きでクラスをマージする¶
特定の条件が true
の場合にクラスをマージしたい場合があります。これは class
メソッドを介して行うことができます。このメソッドは、クラスを追加したいクラスまたはクラスの配列を含む配列を受け取り、値はブール式です。配列要素が数値キーを持つ場合、レンダリングされるクラスリストに常に含まれます。
コンポーネントに他の属性をマージする必要がある場合は、class
メソッドに merge
メソッドをチェーンすることができます。
Note
マージされた属性を受け取らない他の HTML 要素で条件付きでクラスをコンパイルする必要がある場合は、@class
ディレクティブを使用できます。
非クラス属性のマージ¶
class
属性以外の属性をマージする場合、merge
メソッドに提供される値は属性の「デフォルト」値と見なされます。ただし、class
属性とは異なり、これらの属性は注入された属性値とマージされません。代わりに、上書きされます。例えば、button
コンポーネントの実装は次のようになります。
ボタンコンポーネントをカスタム type
でレンダリングするには、コンポーネントを使用するときに指定できます。タイプが指定されていない場合は、button
タイプが使用されます。
この例のボタンコンポーネントのレンダリングされた HTML は次のようになります。
class
以外の属性にデフォルト値と注入された値を結合する場合は、prepends
メソッドを使用できます。この例では、data-controller
属性は常に profile-controller
で始まり、追加の注入された data-controller
値はこのデフォルト値の後に配置されます。
<div {{ $attributes->merge(['data-controller' => $attributes->prepends('profile-controller')]) }}>
{{ $slot }}
</div>
属性の取得とフィルタリング¶
filter
メソッドを使用して属性をフィルタリングできます。このメソッドは、属性を保持したい場合に true
を返すクロージャを受け取ります。
便宜上、whereStartsWith
メソッドを使用して、キーが指定された文字列で始まるすべての属性を取得できます。
逆に、whereDoesntStartWith
メソッドを使用して、キーが指定された文字列で始まるすべての属性を除外できます。
first
メソッドを使用して、指定された属性バッグ内の最初の属性をレンダリングできます。
コンポーネントに属性が存在するかどうかを確認する場合は、has
メソッドを使用できます。このメソッドは、属性名を唯一の引数として受け取り、属性が存在するかどうかを示すブール値を返します。
has
メソッドに配列が渡された場合、メソッドは指定されたすべての属性がコンポーネントに存在するかどうかを判断します。
hasAny
メソッドを使用して、指定された属性のいずれかがコンポーネントに存在するかどうかを判断できます。
get
メソッドを使用して、特定の属性の値を取得できます。
予約語¶
デフォルトでは、いくつかのキーワードが Blade の内部使用のために予約されています。これらのキーワードは、コンポーネント内でパブリックプロパティまたはメソッド名として定義することはできません。
data
render
resolveView
shouldRender
view
withAttributes
withName
スロット¶
多くの場合、"スロット" を介してコンポーネントに追加のコンテンツを渡す必要があります。コンポーネントスロットは、$slot
変数をエコーすることでレンダリングされます。この概念を探るために、alert
コンポーネントが次のマークアップを持つと想像してみましょう。
<!-- /resources/views/components/alert.blade.php -->
<div class="alert alert-danger">
{{ $slot }}
</div>
コンポーネントにコンテンツを渡すために、コンポーネントにコンテンツを注入することができます。
場合によっては、コンポーネント内の異なる場所に複数の異なるスロットをレンダリングする必要があるかもしれません。アラートコンポーネントを修正して、"title" スロットの注入を許可してみましょう。
<!-- /resources/views/components/alert.blade.php -->
<span class="alert-title">{{ $title }}</span>
<div class="alert alert-danger">
{{ $slot }}
</div>
x-slot
タグを使用して、名前付きスロットのコンテンツを定義できます。明示的な x-slot
タグ内にないコンテンツは、$slot
変数にコンポーネントに渡されます。
<x-alert>
<x-slot:title>
Server Error
</x-slot>
<strong>Whoops!</strong> Something went wrong!
</x-alert>
スロットの isEmpty
メソッドを呼び出して、スロットにコンテンツが含まれているかどうかを判断できます。
<span class="alert-title">{{ $title }}</span>
<div class="alert alert-danger">
@if ($slot->isEmpty())
This is default content if the slot is empty.
@else
{{ $slot }}
@endif
</div>
さらに、hasActualContent
メソッドを使用して、スロットに HTML コメントではない "実際の" コンテンツが含まれているかどうかを判断できます。
スコープ付きスロット¶
Vue などの JavaScript フレームワークを使用したことがある場合、スロット内からコンポーネントのデータやメソッドにアクセスできる "スコープ付きスロット" に慣れているかもしれません。Laravel では、コンポーネントにパブリックメソッドやプロパティを定義し、スロット内から $component
変数を介してコンポーネントにアクセスすることで、同様の動作を実現できます。この例では、x-alert
コンポーネントに formatAlert
メソッドがコンポーネントクラスに定義されていると仮定します。
<x-alert>
<x-slot:title>
{{ $component->formatAlert('Server Error') }}
</x-slot>
<strong>Whoops!</strong> Something went wrong!
</x-alert>
スロット属性¶
Blade コンポーネントと同様に、CSS クラス名などの追加の 属性 をスロットに割り当てることができます。
<x-card class="shadow-sm">
<x-slot:heading class="font-bold">
Heading
</x-slot>
Content
<x-slot:footer class="text-sm">
Footer
</x-slot>
</x-card>
スロット属性とやり取りするには、スロットの変数の attributes
プロパティにアクセスできます。属性とのやり取りの詳細については、コンポーネント属性 のドキュメントを参照してください。
@props([
'heading',
'footer',
])
<div {{ $attributes->class(['border']) }}>
<h1 {{ $heading->attributes->class(['text-lg']) }}>
{{ $heading }}
</h1>
{{ $slot }}
<footer {{ $footer->attributes->class(['text-gray-700']) }}>
{{ $footer }}
</footer>
</div>
インラインコンポーネントビュー¶
非常に小さなコンポーネントの場合、コンポーネントクラスとコンポーネントのビューテンプレートの両方を管理するのは面倒かもしれません。そのため、render
メソッドから直接コンポーネントのマークアップを返すことができます。
/**
* Get the view / contents that represent the component.
*/
public function render(): string
{
return <<<'blade'
<div class="alert alert-danger">
{{ $slot }}
</div>
blade;
}
インラインビューコンポーネントの生成¶
インラインビューをレンダリングするコンポーネントを作成するには、make:component
コマンドを実行する際に inline
オプションを使用できます。
動的コンポーネント¶
コンポーネントをレンダリングする必要があるが、どのコンポーネントをレンダリングするかが実行時までわからない場合があります。このような状況では、Laravel の組み込みの dynamic-component
コンポーネントを使用して、実行時の値または変数に基づいてコンポーネントをレンダリングできます。
// $componentName = "secondary-button";
<x-dynamic-component :component="$componentName" class="mt-4" />
コンポーネントの手動登録¶
Warning
以下のコンポーネントの手動登録に関するドキュメントは、ビューコンポーネントを含む Laravel パッケージを作成している場合に主に適用されます。パッケージを作成していない場合、この部分のコンポーネントドキュメントはあまり関係がないかもしれません。
独自のアプリケーション用のコンポーネントを作成する場合、コンポーネントは app/View/Components
ディレクトリと resources/views/components
ディレクトリ内で自動的に検出されます。
ただし、Blade コンポーネントを利用するパッケージを作成している場合や、コンポーネントを非標準的なディレクトリに配置している場合、コンポーネントクラスとその HTML タグエイリアスを手動で登録して、Laravel がコンポーネントを見つけられるようにする必要があります。通常、コンポーネントはパッケージのサービスプロバイダの boot
メソッドで登録します。
use Illuminate\Support\Facades\Blade;
use VendorPackage\View\Components\AlertComponent;
/**
* Bootstrap your package's services.
*/
public function boot(): void
{
Blade::component('package-alert', AlertComponent::class);
}
コンポーネントが登録されると、タグエイリアスを使ってレンダリングできます。
パッケージコンポーネントの自動読み込み¶
代わりに、componentNamespace
メソッドを使用して、規約に基づいてコンポーネントクラスを自動読み込みすることもできます。たとえば、Nightshade
パッケージには Package\Views\Components
名前空間内に Calendar
と ColorPicker
コンポーネントがあるとします。
use Illuminate\Support\Facades\Blade;
/**
* Bootstrap your package's services.
*/
public function boot(): void
{
Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
}
これにより、package-name::
構文を使用してベンダー名前空間でパッケージコンポーネントを使用できます。
Blade は、コンポーネント名をパスカルケースにして、このコンポーネントにリンクされたクラスを自動的に検出します。サブディレクトリも "ドット" 表記でサポートされています。
匿名コンポーネント¶
インラインコンポーネントと同様に、匿名コンポーネントは単一のファイルを介してコンポーネントを管理するメカニズムを提供します。ただし、匿名コンポーネントは単一のビューファイルを使用し、関連するクラスはありません。匿名コンポーネントを定義するには、Blade テンプレートを resources/views/components
ディレクトリに配置するだけです。たとえば、resources/views/components/alert.blade.php
にコンポーネントを定義した場合、次のようにレンダリングできます。
コンポーネントが components
ディレクトリ内のより深い階層にネストされている場合、.
文字を使用してコンポーネントを示すことができます。たとえば、コンポーネントが resources/views/components/inputs/button.blade.php
に定義されている場合、次のようにレンダリングできます。
匿名インデックスコンポーネント¶
コンポーネントが多くの Blade テンプレートで構成されている場合、特定のコンポーネントのテンプレートを単一のディレクトリ内にグループ化したい場合があります。たとえば、"accordion" コンポーネントが次のディレクトリ構造を持っているとします。
/resources/views/components/accordion.blade.php
/resources/views/components/accordion/item.blade.php
このディレクトリ構造により、次のようにアコーディオンコンポーネントとそのアイテムをレンダリングできます。
ただし、x-accordion
を介してアコーディオンコンポーネントをレンダリングするために、"index" アコーディオンコンポーネントテンプレートを resources/views/components
ディレクトリに配置する必要がありました。これは、他のアコーディオン関連のテンプレートと一緒に accordion
ディレクトリ内にネストされているのではなく、配置する必要がありました。
幸いなことに、Blade ではコンポーネントのテンプレートディレクトリ内に index.blade.php
ファイルを配置できます。コンポーネントの index.blade.php
テンプレートが存在する場合、それはコンポーネントの "ルート" ノードとしてレンダリングされます。したがって、上記の例で与えられた同じ Blade 構文を使用し続けることができますが、ディレクトリ構造を次のように調整します。
/resources/views/components/accordion/index.blade.php
/resources/views/components/accordion/item.blade.php
データプロパティ / 属性¶
匿名コンポーネントには関連するクラスがないため、どのデータを変数としてコンポーネントに渡すべきか、どの属性をコンポーネントの 属性バッグ に配置するべきかを区別する方法が気になるかもしれません。
コンポーネントの Blade テンプレートの先頭で @props
ディレクティブを使用して、データ変数として扱うべき属性を指定できます。コンポーネント上の他のすべての属性は、コンポーネントの属性バッグを介して利用できます。データ変数にデフォルト値を指定したい場合は、変数名を配列キーとして、デフォルト値を配列値として指定できます。
<!-- /resources/views/components/alert.blade.php -->
@props(['type' => 'info', 'message'])
<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
{{ $message }}
</div>
上記のコンポーネント定義に基づいて、次のようにコンポーネントをレンダリングできます。
親データへのアクセス¶
子コンポーネント内から親コンポーネントのデータにアクセスしたい場合があります。このような場合、@aware
ディレクティブを使用できます。たとえば、親 <x-menu>
と子 <x-menu.item>
で構成される複雑なメニューコンポーネントを構築しているとします。
<x-menu>
コンポーネントは次のようになります。
<!-- /resources/views/components/menu/index.blade.php -->
@props(['color' => 'gray'])
<ul {{ $attributes->merge(['class' => 'bg-'.$color.'-200']) }}>
{{ $slot }}
</ul>
<x-menu.item>
コンポーネント内から親の color
属性にアクセスするには、コンポーネントの Blade テンプレート内で @aware
ディレクティブを使用します。
<!-- /resources/views/components/menu/item.blade.php -->
@aware(['color' => 'gray'])
<li {{ $attributes->merge(['class' => 'text-'.$color.'-800']) }}>
{{ $slot }}
</li>
<x-menu>
コンポーネントは、以下のような実装を持つかもしれません:
<!-- /resources/views/components/menu/index.blade.php -->
@props(['color' => 'gray'])
<ul {{ $attributes->merge(['class' => 'bg-'.$color.'-200']) }}>
{{ $slot }}
</ul>
color
プロパティは親 (<x-menu>
) にのみ渡されるため、<x-menu.item>
内では利用できません。しかし、@aware
ディレクティブを使用することで、<x-menu.item>
内でも利用できるようになります:
<!-- /resources/views/components/menu/item.blade.php -->
@aware(['color' => 'gray'])
<li {{ $attributes->merge(['class' => 'text-'.$color.'-800']) }}>
{{ $slot }}
</li>
Warning
@aware
ディレクティブは、HTML属性を介して親コンポーネントに明示的に渡されていない親データにはアクセスできません。親コンポーネントに明示的に渡されていないデフォルトの @props
値には、@aware
ディレクティブからアクセスできません。
匿名コンポーネントのパス¶
前述のように、匿名コンポーネントは通常、resources/views/components
ディレクトリ内にBladeテンプレートを配置することで定義されます。しかし、デフォルトのパスに加えて、Laravelに他の匿名コンポーネントのパスを登録したい場合があります。
anonymousComponentPath
メソッドは、匿名コンポーネントの場所の「パス」を最初の引数として受け取り、コンポーネントが配置されるオプションの「名前空間」を2番目の引数として受け取ります。通常、このメソッドは、アプリケーションのサービスプロバイダの boot
メソッドから呼び出す必要があります:
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Blade::anonymousComponentPath(__DIR__.'/../components');
}
上記の例のように、コンポーネントパスが指定されたプレフィックスなしで登録されている場合、Bladeコンポーネントで対応するプレフィックスなしでレンダリングできます。例えば、上記のパスに panel.blade.php
コンポーネントが存在する場合、以下のようにレンダリングできます:
anonymousComponentPath
メソッドの2番目の引数としてプレフィックス「名前空間」を指定できます:
Blade::anonymousComponentPath(__DIR__.'/../components', 'dashboard');
プレフィックスが提供されると、その「名前空間」内のコンポーネントは、コンポーネントをレンダリングする際にコンポーネント名に名前空間をプレフィックスとして付けることでレンダリングできます:
レイアウトの構築¶
コンポーネントを使用したレイアウト¶
ほとんどのWebアプリケーションは、さまざまなページで同じ一般的なレイアウトを維持します。すべてのビューでレイアウト全体のHTMLを繰り返す必要がある場合、アプリケーションのメンテナンスは非常に面倒で困難になります。幸いなことに、このレイアウトを単一の Bladeコンポーネント として定義し、アプリケーション全体で使用することが便利です。
レイアウトコンポーネントの定義¶
例えば、「todo」リストアプリケーションを構築していると想像してください。以下のような layout
コンポーネントを定義するかもしれません:
<!-- resources/views/components/layout.blade.php -->
<html>
<head>
<title>{{ $title ?? 'Todo Manager' }}</title>
</head>
<body>
<h1>Todos</h1>
<hr/>
{{ $slot }}
</body>
</html>
レイアウトコンポーネントの適用¶
layout
コンポーネントが定義されたら、そのコンポーネントを利用するBladeビューを作成できます。この例では、タスクリストを表示するシンプルなビューを定義します:
<!-- resources/views/tasks.blade.php -->
<x-layout>
@foreach ($tasks as $task)
<div>{{ $task }}</div>
@endforeach
</x-layout>
コンポーネントに注入されたコンテンツは、layout
コンポーネント内のデフォルトの $slot
変数に提供されます。お気づきのように、layout
は $title
スロットが提供された場合にも対応します。そうでない場合は、デフォルトのタイトルが表示されます。タスクリストビューからカスタムタイトルを注入するには、コンポーネントドキュメントで説明されている標準のスロット構文を使用します:
<!-- resources/views/tasks.blade.php -->
<x-layout>
<x-slot:title>
Custom Title
</x-slot>
@foreach ($tasks as $task)
<div>{{ $task }}</div>
@endforeach
</x-layout>
レイアウトとタスクリストビューを定義したら、ルートから task
ビューを返すだけです:
use App\Models\Task;
Route::get('/tasks', function () {
return view('tasks', ['tasks' => Task::all()]);
});
テンプレート継承を使用したレイアウト¶
レイアウトの定義¶
レイアウトは、「テンプレート継承」を介しても作成できます。これは、コンポーネントが導入される前にアプリケーションを構築するための主要な方法でした。
まず、簡単な例を見てみましょう。最初に、ページレイアウトを見てみましょう。ほとんどのWebアプリケーションは、さまざまなページで同じ一般的なレイアウトを維持するため、このレイアウトを単一のBladeビューとして定義すると便利です:
<!-- resources/views/layouts/app.blade.php -->
<html>
<head>
<title>App Name - @yield('title')</title>
</head>
<body>
@section('sidebar')
This is the master sidebar.
@show
<div class="container">
@yield('content')
</div>
</body>
</html>
このファイルには、典型的なHTMLマークアップが含まれています。ただし、@section
および @yield
ディレクティブに注意してください。@section
ディレクティブは、名前が示すように、コンテンツのセクションを定義し、@yield
ディレクティブは、指定されたセクションの内容を表示するために使用されます。
これで、アプリケーションのレイアウトを定義したので、子ビューを定義しましょう。
レイアウトの拡張¶
子ビューを定義する際に、@extends
Bladeディレクティブを使用して、子ビューがどのレイアウトを「継承」するかを指定します。レイアウトを継承するビューは、@section
ディレクティブを使用してレイアウトのセクションにコンテンツを注入できます。前述の例で見たように、これらのセクションの内容は @yield
を使用してレイアウトに表示されます:
<!-- resources/views/child.blade.php -->
@extends('layouts.app')
@section('title', 'Page Title')
@section('sidebar')
@@parent
<p>This is appended to the master sidebar.</p>
@endsection
@section('content')
<p>This is my body content.</p>
@endsection
この例では、sidebar
セクションは @@parent
ディレクティブを使用して、レイアウトのサイドバーにコンテンツを追加(上書きではなく)しています。@@parent
ディレクティブは、ビューがレンダリングされるときにレイアウトのコンテンツに置き換えられます。
Note
前述の例とは異なり、この sidebar
セクションは @endsection
で終わります。@show
ではなく。@endsection
ディレクティブはセクションを定義するだけですが、@show
はセクションを定義し、すぐにセクションを表示します。
@yield
ディレクティブは、2番目のパラメータとしてデフォルト値も受け取ります。この値は、生成されるセクションが未定義の場合にレンダリングされます:
フォーム¶
CSRFフィールド¶
アプリケーションでHTMLフォームを定義する際には、CSRF保護ミドルウェアがリクエストを検証できるように、フォームに隠しCSRFトークンフィールドを含める必要があります。@csrf
Bladeディレクティブを使用して、トークンフィールドを生成できます:
メソッドフィールド¶
HTMLフォームは PUT
、PATCH
、または DELETE
リクエストを作成できないため、これらのHTTP動詞を偽装するために隠し _method
フィールドを追加する必要があります。@method
Bladeディレクティブは、このフィールドを作成できます:
バリデーションエラー¶
@error
ディレクティブは、指定された属性に対して バリデーションエラーメッセージ が存在するかどうかをすばやく確認するために使用できます。@error
ディレクティブ内では、エラーメッセージを表示するために $message
変数を出力できます:
<!-- /resources/views/post/create.blade.php -->
<label for="title">Post Title</label>
<input id="title"
type="text"
class="@error('title') is-invalid @enderror">
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
@error
ディレクティブは "if" 文にコンパイルされるため、属性にエラーがない場合にコンテンツをレンダリングするために @else
ディレクティブを使用できます:
<!-- /resources/views/auth.blade.php -->
<label for="email">Email address</label>
<input id="email"
type="email"
class="@error('email') is-invalid @else is-valid @enderror">
特定のエラーバッグの名前を @error
ディレクティブの2番目のパラメータとして渡すことで、複数のフォームを含むページでバリデーションエラーメッセージを取得できます:
<!-- /resources/views/auth.blade.php -->
<label for="email">Email address</label>
<input id="email"
type="email"
class="@error('email', 'login') is-invalid @enderror">
@error('email', 'login')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
スタック¶
Bladeでは、他のビューやレイアウトの別の場所でレンダリングできる名前付きスタックにプッシュできます。これは、子ビューに必要なJavaScriptライブラリを指定するのに特に便利です:
指定されたブール式が true
と評価された場合にコンテンツを @push
したい場合、@pushIf
ディレクティブを使用できます:
必要なだけ何度でもスタックにプッシュできます。スタックの完全な内容をレンダリングするには、スタックの名前を @stack
ディレクティブに渡します:
スタックの先頭にコンテンツを追加したい場合は、@prepend
ディレクティブを使用する必要があります:
サービスの注入¶
@inject
ディレクティブを使用して、Laravelのサービスコンテナからサービスを取得できます。@inject
に渡される最初の引数は、サービスが配置される変数の名前で、2番目の引数は解決したいサービスのクラスまたはインターフェース名です:
@inject('metrics', 'App\Services\MetricsService')
<div>
月間収益: {{ $metrics->monthlyRevenue() }}.
</div>
インライン Blade テンプレートのレンダリング¶
時々、生の Blade テンプレート文字列を有効な HTML に変換する必要があるかもしれません。これは、Blade
ファサードによって提供される render
メソッドを使用して行うことができます。render
メソッドは、Blade テンプレート文字列と、テンプレートに提供するオプションのデータ配列を受け取ります:
use Illuminate\Support\Facades\Blade;
return Blade::render('Hello, {{ $name }}', ['name' => 'Julian Bashir']);
Laravel はインライン Blade テンプレートを storage/framework/views
ディレクトリに書き込んでレンダリングします。Blade テンプレートをレンダリングした後にこれらの一時ファイルを削除したい場合は、メソッドに deleteCachedView
引数を指定できます:
Blade フラグメントのレンダリング¶
Turbo や htmx などのフロントエンドフレームワークを使用する場合、HTTP レスポンス内で Blade テンプレートの一部のみを返す必要があることがあります。Blade "フラグメント" を使用すると、それが可能になります。まず、Blade テンプレートの一部を @fragment
と @endfragment
ディレクティブ内に配置します:
@fragment('user-list')
<ul>
@foreach ($users as $user)
<li>{{ $user->name }}</li>
@endforeach
</ul>
@endfragment
そして、このテンプレートを使用するビューをレンダリングする際に、fragment
メソッドを呼び出して、指定されたフラグメントのみが送信される HTTP レスポンスに含まれるように指定できます:
fragmentIf
メソッドを使用すると、指定された条件に基づいてビューのフラグメントを条件付きで返すことができます。それ以外の場合は、ビュー全体が返されます:
return view('dashboard', ['users' => $users])
->fragmentIf($request->hasHeader('HX-Request'), 'user-list');
fragments
および fragmentsIf
メソッドを使用すると、複数のビューフラグメントをレスポンスで返すことができます。フラグメントは連結されます:
view('dashboard', ['users' => $users])
->fragments(['user-list', 'comment-list']);
view('dashboard', ['users' => $users])
->fragmentsIf(
$request->hasHeader('HX-Request'),
['user-list', 'comment-list']
);
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
{
/**
* 任意のアプリケーションサービスの登録。
*/
public function register(): void
{
// ...
}
/**
* 任意のアプリケーションサービスのブートストラップ。
*/
public function boot(): void
{
Blade::directive('datetime', function (string $expression) {
return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
});
}
}
見ての通り、ディレクティブに渡された式に format
メソッドを連鎖させます。したがって、この例では、このディレクティブによって生成される最終的な PHP は次のようになります:
<?php echo ($var)->format('m/d/Y H:i'); ?>
Warning
Blade ディレクティブのロジックを更新した後、キャッシュされたすべての Blade ビューを削除する必要があります。キャッシュされた Blade ビューは、view:clear
Artisan コマンドを使用して削除できます。
カスタムエコーハンドラ¶
Blade を使用してオブジェクトを "echo" しようとすると、オブジェクトの __toString
メソッドが呼び出されます。__toString
メソッドは、PHP の組み込みの "マジックメソッド" の1つです。ただし、場合によっては、特定のクラスの __toString
メソッドを制御できないことがあります。たとえば、対話しているクラスがサードパーティのライブラリに属している場合などです。
このような場合、Blade ではその特定のタイプのオブジェクトのカスタムエコーハンドラを登録できます。これを行うには、Blade の stringable
メソッドを呼び出します。stringable
メソッドはクロージャを受け取ります。このクロージャは、レンダリングを担当するオブジェクトのタイプをタイプヒントする必要があります。通常、stringable
メソッドは、アプリケーションの AppServiceProvider
クラスの boot
メソッド内で呼び出されるべきです:
use Illuminate\Support\Facades\Blade;
use Money\Money;
/**
* 任意のアプリケーションサービスのブートストラップ。
*/
public function boot(): void
{
Blade::stringable(function (Money $money) {
return $money->formatTo('en_GB');
});
}
カスタムエコーハンドラが定義されると、Blade テンプレート内でオブジェクトを単純に echo できます:
カスタム If ステートメント¶
カスタムディレクティブをプログラミングすることは、単純なカスタム条件ステートメントを定義する場合には必要以上に複雑なことがあります。そのため、Blade は Blade::if
メソッドを提供しており、クロージャを使用してカスタム条件ディレクティブをすばやく定義できます。たとえば、アプリケーションに設定されたデフォルトの "ディスク" をチェックするカスタム条件を定義しましょう。これは、AppServiceProvider
の boot
メソッドで行うことができます:
use Illuminate\Support\Facades\Blade;
/**
* 任意のアプリケーションサービスのブートストラップ。
*/
public function boot(): void
{
Blade::if('disk', function (string $value) {
return config('filesystems.default') === $value;
});
}
カスタム条件が定義されると、テンプレート内でそれを使用できます:
@disk('local')
<!-- アプリケーションはローカルディスクを使用しています... -->
@elsedisk('s3')
<!-- アプリケーションは s3 ディスクを使用しています... -->
@else
<!-- アプリケーションは他のディスクを使用しています... -->
@enddisk
@unlessdisk('local')
<!-- アプリケーションはローカルディスクを使用していません... -->
@enddisk