ブレードテンプレート
- はじめに
- データの表示
- 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
変数の内容を次のように表示できます。
Hello, {{ $name }}.
Bladeの{{ }}
エコー文は、XSS攻撃を防ぐために、自動的にPHPのhtmlspecialchars
関数を通過します。
ビューに渡された変数の内容を表示するだけではありません。任意のPHP関数の結果をエコーすることもできます。実際、Bladeのエコー文の中に任意のPHPコードを入れることができます。
The current UNIX timestamp is {{ time() }}.
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{ /** * Bootstrap any application services. */ public function boot(): void { Blade::withoutDoubleEncoding(); }}
エスケープされていないデータの表示
デフォルトでは、Bladeの{{ }}
文は、XSS攻撃を防ぐために、自動的にPHPのhtmlspecialchars
関数を通過します。データのエスケープを望まない場合は、次の構文を使用できます。
Hello, {!! $name !!}.
アプリケーションのユーザーから提供されたコンテンツをエコーする際は、細心の注意を払ってください。ユーザーが提供したデータを表示する際には、通常、エスケープされた二重波括弧構文を使用してXSS攻撃を防ぐ必要があります。
BladeとJavaScriptフレームワーク
多くのJavaScriptフレームワークも、特定の式をブラウザに表示する必要があることを示すために「波括弧」を使用しているため、@
記号を使用して、Bladeレンダリングエンジンに式をそのまま残すように指示できます。たとえば
<h1>Laravel</h1> Hello, @{{ name }}.
この例では、@
記号はBladeによって削除されますが、{{ name }}
式はBladeエンジンによってそのまま残され、JavaScriptフレームワークによってレンダリングされることができます。
@
記号を使用して、Bladeディレクティブをエスケープすることもできます。
{{-- Blade template --}}@@if() <!-- HTML output -->@if()
JSONのレンダリング
JavaScript変数を初期化するために、配列をビューに渡し、JSONとしてレンダリングすることを意図することがあります。たとえば
<script> var app = <?php echo json_encode($array); ?>;</script>
ただし、json_encode
を手動で呼び出す代わりに、Illuminate\Support\Js::from
メソッドディレクティブを使用できます。from
メソッドは、PHPのjson_encode
関数と同じ引数を受け取りますが、結果のJSONがHTMLの引用符内に正しくエスケープされるようにします。from
メソッドは、指定されたオブジェクトまたは配列を有効なJavaScriptオブジェクトに変換する文字列JSON.parse
JavaScript文を返します。
<script> var app = {{ Illuminate\Support\Js::from($array) }};</script>
最新バージョンのLaravelアプリケーションスケルトンには、Js
ファサードが含まれており、Bladeテンプレート内でこの機能に簡単にアクセスできます。
<script> var app = {{ Js::from($array) }};</script>
Js::from
メソッドは、既存の変数をJSONとしてレンダリングする場合にのみ使用してください。Bladeテンプレートは正規表現に基づいており、複雑な式をディレクティブに渡そうとすると、予期しないエラーが発生する可能性があります。
@verbatim
ディレクティブ
テンプレートの大きな部分でJavaScript変数を表示する場合は、各Bladeエコー文に@
記号を付ける必要がないように、HTMLを@verbatim
ディレクティブで囲むことができます。
@verbatim <div class="container"> Hello, {{ name }}. </div>@endverbatim
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
ディレクティブも提供します。
@unless (Auth::check()) You are not signed in.@endunless
すでに説明した条件ディレクティブに加えて、@isset
および@empty
ディレクティブは、それぞれのPHP関数に対する便利なショートカットとして使用できます。
@isset($records) // $records is defined and is not null...@endisset @empty($records) // $records is "empty"...@endempty
認証ディレクティブ
@auth
および@guest
ディレクティブを使用して、現在のユーザーが認証済みであるか、ゲストであるかをすばやく判断できます。
@auth // The user is authenticated...@endauth @guest // The user is not authenticated...@endguest
必要に応じて、@auth
および@guest
ディレクティブを使用する際にチェックする必要がある認証ガードを指定できます。
@auth('admin') // The user is authenticated...@endauth @guest('admin') // The user is not authenticated...@endguest
環境ディレクティブ
@production
ディレクティブを使用して、アプリケーションが本番環境で実行されているかどうかを確認できます。
@production // Production specific content...@endproduction
または、@env
ディレクティブを使用して、アプリケーションが特定の環境で実行されているかどうかを確認できます。
@env('staging') // The application is running in "staging"...@endenv @env(['staging', 'production']) // The application is running in "staging" or "production"...@endenv
セクションディレクティブ
@hasSection
ディレクティブを使用して、テンプレート継承セクションにコンテンツがあるかどうかを確認できます。
@hasSection('navigation') <div class="pull-right"> @yield('navigation') </div> <div class="clearfix"></div>@endif
sectionMissing
ディレクティブを使用して、セクションにコンテンツがないかどうかを確認できます。
@sectionMissing('navigation') <div class="pull-right"> @include('default-navigation') </div>@endif
セッションディレクティブ
@session
ディレクティブを使用して、セッション値が存在するかどうかを確認できます。セッション値が存在する場合は、@session
および@endsession
ディレクティブ内のテンプレートコンテンツが評価されます。@session
ディレクティブの内容内では、$value
変数をエコーしてセッション値を表示できます。
@session('status') <div class="p-4 bg-green-100"> {{ $value }} </div>@endsession
switch文
@switch
、@case
、@break
、@default
、@endswitch
ディレクティブを使用して、switch文を構築できます。
@switch($i) @case(1) First case... @break @case(2) Second case... @break @default Default case...@endswitch
ループ
条件文に加えて、BladeはPHPのループ構造を操作するための簡単なディレクティブを提供します。繰り返しますが、これらのディレクティブは、PHPの対応物と同様に機能します。
@for ($i = 0; $i < 10; $i++) The current value is {{ $i }}@endfor @foreach ($users as $user) <p>This is user {{ $user->id }}</p>@endforeach @forelse ($users as $user) <li>{{ $user->name }}</li>@empty <p>No users</p>@endforelse @while (true) <p>I'm looping forever.</p>@endwhile
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) This is the first iteration. @endif @if ($loop->last) This is the last iteration. @endif <p>This is user {{ $user->id }}</p>@endforeach
入れ子になったループ内にある場合、parent
プロパティを使用して親ループの$loop
変数にアクセスできます。
@foreach ($users as $user) @foreach ($user->posts as $post) @if ($loop->parent->first) This is the first iteration of the parent loop. @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
を出力します。
<input type="checkbox" name="active" value="active" @checked(old('active', $user->active))/>
同様に、@selected
ディレクティブを使用して、特定のセレクトオプションが「選択済み」かどうかを示すことができます。
<select name="version"> @foreach ($product->versions as $version) <option value="{{ $version }}" @selected(old('version') == $version)> {{ $version }} </option> @endforeach</select>
さらに、@disabled
ディレクティブを使用して、特定の要素を「無効」にするかどうかを示すことができます。
<button type="submit" @disabled($errors->isNotEmpty())>Submit</button>
さらに、@readonly
ディレクティブを使用して、特定の要素を「読み取り専用」にするかどうかを示すことができます。
<input type="email" name="email" @readonly($user->isNotAdmin())/>
さらに、@required
ディレクティブを使用して、特定の要素を「必須」にするかどうかを示すことができます。
<input type="text" name="title" value="title" @required($user->isAdmin())/>
サブビューのインクルード
@include
ディレクティブを使用できますが、Bladeのコンポーネントは同様の機能を提供し、データおよび属性バインディングなど、@include
ディレクティブよりもいくつかの利点を提供します。
Bladeの@include
ディレクティブを使用すると、別のビュー内からBladeビューを含めることができます。親ビューで使用可能なすべての変数は、含まれるビューでも使用可能になります。
<div> @include('shared.errors') <form> <!-- Form Contents --> </form></div>
含まれるビューは親ビューで使用可能なすべてのデータを引き継ぎますが、含まれるビューで使用可能にする追加データの配列を渡すこともできます。
@include('view.name', ['status' => 'complete'])
存在しないビューを@include
しようとすると、Laravelはエラーをスローします。存在する可能性のあるビューと存在しない可能性のあるビューの両方を含めたい場合は、@includeIf
ディレクティブを使用する必要があります。
@includeIf('view.name', ['status' => 'complete'])
特定のブール式がtrue
またはfalse
と評価された場合にビューを@include
する場合は、@includeWhen
および@includeUnless
ディレクティブを使用できます。
@includeWhen($boolean, 'view.name', ['status' => 'complete']) @includeUnless($boolean, 'view.name', ['status' => 'complete'])
指定されたビューの配列から最初に存在するビューを含めるには、includeFirst
ディレクティブを使用できます。
@includeFirst(['custom.admin', 'admin'], ['status' => 'complete'])
Bladeビューでは、__DIR__
および__FILE__
定数の使用を避ける必要があります。これらは、キャッシュされたコンパイル済みビューの場所に参照されます。
コレクションのビューのレンダリング
Bladeの@each
ディレクティブを使用して、ループとインクルードを1行にまとめることができます。
@each('view.name', $jobs, 'job')
@each
ディレクティブの最初の引数は、配列またはコレクション内の各要素に対してレンダリングするビューです。2番目の引数は、反復処理する配列またはコレクションであり、3番目の引数は、ビュー内で現在の反復処理に割り当てられる変数名です。たとえば、jobs
の配列を反復処理する場合は、通常、ビュー内で各ジョブにjob
変数としてアクセスすることをお勧めします。現在の反復処理の配列キーは、ビュー内でkey
変数として使用できます。
@each
ディレクティブに4番目の引数を渡すこともできます。この引数は、指定された配列が空の場合にレンダリングされるビューを決定します。
@each('view.name', $jobs, 'job', 'view.empty')
@each
を使用してレンダリングされたビューは、親ビューからの変数を継承しません。子ビューでこれらの変数が必要な場合は、代わりに@foreach
および@include
ディレクティブを使用する必要があります。
@once
ディレクティブ
@once
ディレクティブを使用すると、レンダリングサイクルごとに1回だけ評価されるテンプレートの部分を定義できます。これは、スタックを使用して特定のJavaScriptをページのヘッダーにプッシュする場合に役立ちます。たとえば、ループ内で特定のコンポーネントをレンダリングしている場合、コンポーネントが最初にレンダリングされたときにのみJavaScriptをヘッダーにプッシュすることがあります。
@once @push('scripts') <script> // Your custom JavaScript... </script> @endpush@endonce
@once
ディレクティブは多くの場合、@push
または@prepend
ディレクティブと組み合わせて使用されるため、便宜上@pushOnce
および@prependOnce
ディレクティブを使用できます。
@pushOnce('scripts') <script> // Your custom JavaScript... </script>@endPushOnce
生のPHP
状況によっては、ビューにPHPコードを埋め込むことが役立ちます。Bladeの@php
ディレクティブを使用して、テンプレート内でプレーンなPHPのブロックを実行できます。
@php $counter = 1;@endphp
または、クラスのインポートにのみPHPを使用する必要がある場合は、@use
ディレクティブを使用できます。
@use('App\Models\Flight')
インポートされたクラスにエイリアスを付けるには、@use
ディレクティブに2番目の引数を指定できます。
@use('App\Models\Flight', 'FlightModel')
コメント
Bladeでは、ビューにコメントを定義することもできます。ただし、HTMLコメントとは異なり、Bladeコメントはアプリケーションによって返されるHTMLには含まれません。
{{-- This comment will not be present in the rendered HTML --}}
コンポーネント
コンポーネントとスロットは、セクション、レイアウト、インクルードと同様の利点を提供しますが、コンポーネントとスロットのメンタルモデルの方が理解しやすいと感じる人もいます。コンポーネントの作成には、クラスベースのコンポーネントと匿名コンポーネントの2つの方法があります。
クラスベースのコンポーネントを作成するには、make:component
Artisanコマンドを使用できます。コンポーネントの使用方法を説明するために、単純なAlert
コンポーネントを作成します。make:component
コマンドは、コンポーネントをapp/View/Components
ディレクトリに配置します。
php artisan make:component Alert
make:component
コマンドは、コンポーネントのビューテンプレートも作成します。ビューはresources/views/components
ディレクトリに配置されます。独自のアプリケーションのコンポーネントを作成する際に、コンポーネントはapp/View/Components
ディレクトリとresources/views/components
ディレクトリ内で自動的に検出されるため、通常はそれ以上のコンポーネント登録は必要ありません。
サブディレクトリ内にコンポーネントを作成することもできます。
php artisan make:component Forms/Input
上記のコマンドは、app/View/Components/Forms
ディレクトリにInput
コンポーネントを作成し、ビューをresources/views/components/forms
ディレクトリに配置します。
匿名コンポーネント(Bladeテンプレートのみでクラスを持たないコンポーネント)を作成する場合は、make:component
コマンドを呼び出す際に--view
フラグを使用できます。
php artisan make:component forms.input --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; /** * Bootstrap your package's services. */public function boot(): void{ Blade::component('package-alert', Alert::class);}
コンポーネントが登録されると、そのタグエイリアスを使用してレンダリングできます。
<x-package-alert/>
あるいは、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::
構文を使用して、ベンダーの名前空間でパッケージコンポーネントを使用できます。
<x-nightshade::calendar /><x-nightshade::color-picker />
Bladeは、コンポーネント名をパスカルケースに変換することで、このコンポーネントにリンクされているクラスを自動的に検出します。サブディレクトリも「ドット」表記を使用してサポートされます。
コンポーネントのレンダリング
コンポーネントを表示するには、Bladeテンプレートの1つにBladeコンポーネントタグを使用できます。Bladeコンポーネントタグは、文字列x-
で始まり、コンポーネントクラスのケバブケース名が続きます。
<x-alert/> <x-user-profile/>
コンポーネントクラスがapp/View/Components
ディレクトリ内に深くネストされている場合は、ディレクトリのネストを示すために.
文字を使用できます。たとえば、コンポーネントがapp/View/Components/Inputs/Button.php
にあると仮定すると、次のようにレンダリングできます。
<x-inputs.button/>
コンポーネントを条件付きでレンダリングする場合は、コンポーネントクラスにshouldRender
メソッドを定義できます。shouldRender
メソッドがfalse
を返す場合、コンポーネントはレンダリングされません。
use Illuminate\Support\Str; /** * Whether the component should be rendered */public function shouldRender(): bool{ return Str::length($this->message) > 0;}
インデックスコンポーネント
コンポーネントがコンポーネントグループの一部である場合があり、関連するコンポーネントを単一のディレクトリ内にグループ化したい場合があります。たとえば、次のクラス構造を持つ「カード」コンポーネントを考えてみます。
App\Views\Components\Card\CardApp\Views\Components\Card\HeaderApp\Views\Components\Card\Body
ルートCard
コンポーネントはCard
ディレクトリ内にネストされているため、<x-card.card>
を介してコンポーネントをレンダリングする必要があると予想される場合があります。ただし、コンポーネントのファイル名がコンポーネントのディレクトリ名と一致する場合、Laravelは自動的にそのコンポーネントが「ルート」コンポーネントであると仮定し、ディレクトリ名を繰り返さずにコンポーネントをレンダリングできます。
<x-card> <x-card.header>...</x-card.header> <x-card.body>...</x-card.body></x-card>
コンポーネントへのデータの受け渡し
HTML属性を使用して、Bladeコンポーネントにデータを渡すことができます。ハードコーディングされたプリミティブ値は、単純なHTML属性文字列を使用してコンポーネントに渡すことができます。PHP式と変数は、接頭辞として:
文字を使用する属性を介してコンポーネントに渡す必要があります。
<x-alert type="error" :message="$message"/>
コンポーネントのすべてのデータ属性は、そのクラスコンストラクタで定義する必要があります。コンポーネントのパブリックプロパティはすべて、自動的にコンポーネントのビューで使用可能になります。コンポーネントの`render`メソッドからビューにデータを渡す必要はありません。
<?php namespace App\View\Components; use Illuminate\View\Component;use Illuminate\View\View; class Alert extends Component{ /** * Create the component instance. */ public function __construct( public string $type, public string $message, ) {} /** * Get the view / contents that represent the component. */ public function render(): View { return view('components.alert'); }}
コンポーネントがレンダリングされるときに、コンポーネントのパブリック変数の内容を、変数名をエコーすることで表示できます。
<div class="alert alert-{{ $type }}"> {{ $message }}</div>
ケース
コンポーネントコンストラクタの引数は`camelCase`を使用して指定する一方、HTML属性で引数名を参照する際には`kebab-case`を使用する必要があります。例えば、以下のコンポーネントコンストラクタの場合
/** * Create the component instance. */public function __construct( public string $alertType,) {}
`$alertType`引数は、次のようにコンポーネントに渡すことができます。
<x-alert alert-type="danger" />
簡略属性構文
コンポーネントに属性を渡す際に、「簡略属性」構文を使用することもできます。属性名は対応する変数名と一致することが多いため、これは多くの場合便利です。
{{-- Short attribute syntax... --}}<x-profile :$userId :$name /> {{-- Is equivalent to... --}}<x-profile :user-id="$userId" :name="$name" />
属性レンダリングのエスケープ
Alpine.jsなどのJavaScriptフレームワークもコロン接頭辞の属性を使用するため、属性がPHP式ではないことをBladeに知らせるには、二重コロン(`::`)接頭辞を使用できます。例えば、以下のコンポーネントの場合
<x-button ::class="{ danger: isDeleting }"> Submit</x-button>
Bladeによって以下のHTMLがレンダリングされます。
<button :class="{ danger: isDeleting }"> Submit</button>
コンポーネントメソッド
パブリック変数がコンポーネントテンプレートで使用可能になることに加えて、コンポーネントのパブリックメソッドを呼び出すこともできます。例えば、`isSelected`メソッドを持つコンポーネントがあるとします。
/** * Determine if the given option is the currently selected option. */public function isSelected(string $option): bool{ return $option === $this->selected;}
このメソッドは、メソッド名と一致する変数を呼び出すことで、コンポーネントテンプレートから実行できます。
<option {{ $isSelected($value) ? 'selected' : '' }} value="{{ $value }}"> {{ $label }}</option>
コンポーネントクラス内での属性とスロットへのアクセス
Bladeコンポーネントでは、クラスの`render`メソッド内でコンポーネント名、属性、スロットにアクセスすることもできます。ただし、このデータにアクセスするには、コンポーネントの`render`メソッドからクロージャを返す必要があります。
use Closure; /** * Get the view / contents that represent the component. */public function render(): Closure{ return function () { return '<div {{ $attributes }}>Components content</div>'; };}
コンポーネントの`render`メソッドによって返されるクロージャは、唯一の引数として`$data`配列を受け取ることもできます。この配列には、コンポーネントに関する情報を提供するいくつかの要素が含まれます。
return function (array $data) { // $data['componentName']; // $data['attributes']; // $data['slot']; return '<div {{ $attributes }}>Components content</div>';}
`$data`配列の要素は、`render`メソッドによって返されるBlade文字列に直接埋め込まないでください。そうすると、悪意のある属性コンテンツを介してリモートコード実行を許可する可能性があります。
`componentName`は、`x-`接頭辞の後のHTMLタグで使用される名前と同じです。したがって、`
クロージャは文字列を返す必要があります。返された文字列が既存のビューに対応する場合、そのビューがレンダリングされます。そうでない場合、返された文字列はインラインBladeビューとして評価されます。
追加の依存関係
コンポーネントがLaravelの[サービスコンテナ](/docs/11.x/container)から依存関係を必要とする場合、コンポーネントのデータ属性の前にそれらをリストアップすると、コンテナによって自動的に注入されます。
use App\Services\AlertCreator; /** * Create the component instance. */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{ /** * The properties / methods that should not be exposed to the component template. * * @var array */ protected $except = ['type']; /** * Create the component instance. */ public function __construct( public string $type, ) {}}
コンポーネント属性
データ属性をコンポーネントに渡す方法については既に説明しましたが、コンポーネントの機能に必要なデータの一部ではない`class`などの追加のHTML属性を指定する必要がある場合があります。通常、これらの追加属性はコンポーネントテンプレートのルート要素に渡すことが望ましいです。例えば、`alert`コンポーネントを次のようにレンダリングしたいとします。
<x-alert type="error" :message="$message" class="mt-4"/>
コンポーネントコンストラクタの一部ではないすべての属性は、自動的にコンポーネントの「属性バッグ」に追加されます。この属性バッグは、`$attributes`変数を通じてコンポーネントに自動的に使用可能になります。すべての属性はこの変数をエコーすることでコンポーネント内でレンダリングできます。
<div {{ $attributes }}> <!-- Component content --></div>
`@env`などのディレクティブをコンポーネントタグ内で使用することは、現時点ではサポートされていません。例えば、`
デフォルト/マージされた属性
属性のデフォルト値を指定したり、コンポーネントの属性の一部に追加の値をマージしたりする必要がある場合があります。これを実現するには、属性バッグの`merge`メソッドを使用できます。このメソッドは、コンポーネントに常に適用されるデフォルトのCSSクラスのセットを定義する場合に特に役立ちます。
<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}> {{ $message }}</div>
このコンポーネントが次のように使用されると仮定します。
<x-alert type="error" :message="$message" class="mb-4"/>
コンポーネントの最終的なレンダリングされたHTMLは、次のようになります。
<div class="alert alert-error mb-4"> <!-- Contents of the $message variable --></div>
条件付きクラスのマージ
特定の条件が`true`の場合にクラスをマージしたい場合があります。これは、`class`メソッドを使用することで実現できます。このメソッドは、クラスの配列を受け取ります。配列のキーには追加するクラスが含まれ、値はブール式です。配列要素に数値キーがある場合、常にレンダリングされたクラスリストに含まれます。
<div {{ $attributes->class(['p-4', 'bg-red' => $hasError]) }}> {{ $message }}</div>
コンポーネントに他の属性をマージする必要がある場合は、`class`メソッドに`merge`メソッドをチェーンできます。
<button {{ $attributes->class(['p-4'])->merge(['type' => 'button']) }}> {{ $slot }}</button>
マージされた属性を受け取らない他のHTML要素にクラスを条件付きでコンパイルする必要がある場合は、[ `@class`ディレクティブ](#conditional-classes)を使用できます。
クラス以外の属性のマージ
`class`属性以外の属性をマージする場合、`merge`メソッドに提供される値は、属性の「デフォルト」値と見なされます。ただし、`class`属性とは異なり、これらの属性は注入された属性値とマージされません。代わりに、上書きされます。例えば、`button`コンポーネントの実装は次のようになります。
<button {{ $attributes->merge(['type' => 'button']) }}> {{ $slot }}</button>
カスタム`type`でボタンコンポーネントをレンダリングするには、コンポーネントを使用するときに指定できます。 typeを指定しないと、`button` typeが使用されます。
<x-button type="submit"> Submit</x-button>
この例での`button`コンポーネントのレンダリングされたHTMLは次のようになります。
<button type="submit"> Submit</button>
`class`以外の属性で、デフォルト値と注入された値を結合させたい場合は、`prepends`メソッドを使用できます。この例では、`data-controller`属性は常に`profile-controller`で始まり、追加で注入された`data-controller`値はこのデフォルト値の後に配置されます。
<div {{ $attributes->merge(['data-controller' => $attributes->prepends('profile-controller')]) }}> {{ $slot }}</div>
属性の取得とフィルタリング
`filter`メソッドを使用して属性をフィルタリングできます。このメソッドは、属性バッグに属性を保持したい場合に`true`を返すクロージャを受け取ります。
{{ $attributes->filter(fn (string $value, string $key) => $key == 'foo') }}
便宜上、`whereStartsWith`メソッドを使用して、キーが特定の文字列で始まるすべての属性を取得できます。
{{ $attributes->whereStartsWith('wire:model') }}
逆に、`whereDoesntStartWith`メソッドを使用して、キーが特定の文字列で始まるすべての属性を除外できます。
{{ $attributes->whereDoesntStartWith('wire:model') }}
`first`メソッドを使用すると、特定の属性バッグの最初の属性をレンダリングできます。
{{ $attributes->whereStartsWith('wire:model')->first() }}
コンポーネントに属性が存在するかどうかを確認する場合は、`has`メソッドを使用できます。このメソッドは属性名を唯一の引数として受け取り、属性が存在するかどうかを示すブール値を返します。
@if ($attributes->has('class')) <div>Class attribute is present</div>@endif
配列が`has`メソッドに渡された場合、メソッドは指定されたすべての属性がコンポーネントに存在するかどうかを判断します。
@if ($attributes->has(['name', 'class'])) <div>All of the attributes are present</div>@endif
`hasAny`メソッドを使用して、指定された属性のいずれかがコンポーネントに存在するかどうかを判断できます。
@if ($attributes->hasAny(['href', ':href', 'v-bind:href'])) <div>One of the attributes is present</div>@endif
`get`メソッドを使用して、特定の属性の値を取得できます。
{{ $attributes->get('class') }}
予約語
デフォルトでは、コンポーネントをレンダリングするために、Bladeの内部使用のためにいくつかのキーワードが予約されています。以下のキーワードは、コンポーネント内でパブリックプロパティまたはメソッド名として定義できません。
-
data
-
render
-
resolveView
-
shouldRender
-
view
-
withAttributes
-
withName
スロット
多くの場合、「スロット」を介してコンポーネントに追加のコンテンツを渡す必要があります。コンポーネントのスロットは、`$slot`変数をエコーすることでレンダリングされます。この概念を理解するために、`alert`コンポーネントに次のマークアップがあるとします。
<!-- /resources/views/components/alert.blade.php --> <div class="alert alert-danger"> {{ $slot }}</div>
コンポーネントにコンテンツを挿入することで、スロットにコンテンツを渡すことができます。
<x-alert> <strong>Whoops!</strong> Something went wrong!</x-alert>
コンポーネントは、コンポーネント内の異なる場所に複数の異なるスロットをレンダリングする必要がある場合があります。`title`スロットの挿入を許可するように、`alert`コンポーネントを変更してみましょう。
<!-- /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コメントではない「実際の」コンテンツを含むかどうかを確認できます。
@if ($slot->hasActualContent()) The scope has non-comment content.@endif
スコープ付きスロット
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クラス名などの追加の[属性](#component-attributes)をスロットに割り当てることができます。
<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`プロパティにアクセスできます。属性の操作方法の詳細については、[コンポーネント属性](#component-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
オプションを使用できます。
php artisan make:component Alert --inline
動的コンポーネント
実行時までどのコンポーネントをレンダリングすべきかわからない場合があります。このような状況では、Laravel組み込みのdynamic-component
コンポーネントを使用して、実行時の値または変数に基づいてコンポーネントをレンダリングできます。
// $componentName = "secondary-button"; <x-dynamic-component :component="$componentName" class="mt-4" />
コンポーネントの手動登録
コンポーネントの手動登録に関する以下のドキュメントは、主にビューコンポーネントを含む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);}
コンポーネントが登録されると、そのタグエイリアスを使用してレンダリングできます。
<x-package-alert/>
パッケージコンポーネントの自動読み込み
あるいは、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::
構文を使用して、ベンダーの名前空間でパッケージコンポーネントを使用できます。
<x-nightshade::calendar /><x-nightshade::color-picker />
Bladeは、コンポーネント名をパスカルケースに変換することで、このコンポーネントにリンクされているクラスを自動的に検出します。サブディレクトリも「ドット」表記を使用してサポートされます。
匿名コンポーネント
インラインコンポーネントと同様に、匿名コンポーネントは単一ファイルでコンポーネントを管理するためのメカニズムを提供します。ただし、匿名コンポーネントは単一のビューファイルを使用し、関連付けられたクラスはありません。匿名コンポーネントを定義するには、resources/views/components
ディレクトリにBladeテンプレートを配置するだけです。たとえば、resources/views/components/alert.blade.php
にコンポーネントを定義した場合、次のようにレンダリングできます。
<x-alert/>
components
ディレクトリ内でさらに深くネストされているコンポーネントを示すには、.
文字を使用できます。たとえば、コンポーネントがresources/views/components/inputs/button.blade.php
に定義されている場合、次のようにレンダリングできます。
<x-inputs.button/>
匿名インデックスコンポーネント
コンポーネントが多数のBladeテンプレートで構成されている場合、特定のコンポーネントのテンプレートを単一のディレクトリにグループ化したい場合があります。たとえば、次のディレクトリ構造を持つ「accordion」コンポーネントを考えてみましょう。
/resources/views/components/accordion.blade.php/resources/views/components/accordion/item.blade.php
このディレクトリ構造により、次のようにアコーディオンコンポーネントとそのアイテムをレンダリングできます。
<x-accordion> <x-accordion.item> ... </x-accordion.item></x-accordion>
ただし、x-accordion
を使用してアコーディオンコンポーネントをレンダリングするために、「index」アコーディオンコンポーネントテンプレートをresources/views/components
ディレクトリに配置する必要があり、他のアコーディオン関連テンプレートとネストすることができませんでした。
ありがたいことに、Bladeでは、コンポーネントのディレクトリ名と一致するファイルをコンポーネントのディレクトリ自体に配置できます。このテンプレートが存在する場合、ネストされているにもかかわらず、コンポーネントの「ルート」要素としてレンダリングできます。そのため、上記の例で示したBlade構文をそのまま使用できますが、ディレクトリ構造を次のように調整します。
/resources/views/components/accordion/accordion.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>
上記のコンポーネント定義を踏まえると、コンポーネントは次のようにレンダリングできます。
<x-alert type="error" :message="$message" class="mb-4"/>
親データへのアクセス
子コンポーネント内で親コンポーネントのデータにアクセスしたい場合があります。このような場合は、@aware
ディレクティブを使用できます。たとえば、親<x-menu>
と子<x-menu.item>
で構成される複雑なメニューコンポーネントを作成しているとします。
<x-menu color="purple"> <x-menu.item>...</x-menu.item> <x-menu.item>...</x-menu.item></x-menu>
<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>
@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
コンポーネントが存在する場合、次のようにレンダリングできます。
<x-panel />
プレフィックス「名前空間」は、anonymousComponentPath
メソッドの2番目の引数として提供できます。
Blade::anonymousComponentPath(__DIR__.'/../components', 'dashboard');
プレフィックスが提供されている場合、その「名前空間」内のコンポーネントは、コンポーネントがレンダリングされるときに、コンポーネントの名前の前に名前空間のプレフィックスを付けることでレンダリングできます。
<x-dashboard::panel />
レイアウトの構築
コンポーネントを使用したレイアウト
ほとんどのウェブアプリケーションは、さまざまなページで同じ一般的なレイアウトを維持しています。作成するすべてのビューでレイアウト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()]);});
テンプレート継承を使用したレイアウト
レイアウトの定義
レイアウトは、「テンプレート継承」を使用して作成することもできます。これは、コンポーネントが導入される前は、アプリケーションを構築するための主要な方法でした。
始めましょう。簡単な例を見てみましょう。まず、ページレイアウトを見てみましょう。ほとんどのウェブアプリケーションはさまざまなページで同じ一般的なレイアウトを維持しているため、このレイアウトを単一の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ディレクティブを使用して、子ビューが「継承」するレイアウトを指定します。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
ディレクティブは、ビューがレンダリングされるときにレイアウトのコンテンツに置き換えられます。
前の例とは異なり、このsidebar
セクションは@show
ではなく@endsection
で終わっています。@endsection
ディレクティブはセクションを定義するだけであり、@show
はセクションを定義してすぐにyieldします。
@yield
ディレクティブは、2番目のパラメータとしてデフォルト値も受け入れます。この値は、yieldされるセクションが未定義の場合にレンダリングされます。
@yield('content', 'Default content')
フォーム
CSRFフィールド
アプリケーションでHTMLフォームを定義する場合は常に、フォームに非表示のCSRFトークンフィールドを含める必要があります。CSRF保護ミドルウェアがリクエストを検証できるようにするためです。@csrf
Bladeディレクティブを使用して、トークンフィールドを生成できます。
<form method="POST" action="/profile"> @csrf ...</form>
メソッドフィールド
HTMLフォームはPUT
、PATCH
、またはDELETE
リクエストを行うことができないため、これらのHTTP動詞を偽装するために非表示の_method
フィールドを追加する必要があります。@method
Bladeディレクティブを使用すると、このフィールドを作成できます。
<form action="/foo/bar" method="POST"> @method('PUT') ...</form>
バリデーションエラー
@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ライブラリを指定する場合に特に役立ちます。
@push('scripts') <script src="/example.js"></script>@endpush
特定のブール式がtrue
と評価された場合にコンテンツを@push
したい場合は、@pushIf
ディレクティブを使用できます。
@pushIf($shouldPush, 'scripts') <script src="/example.js"></script>@endPushIf
必要に応じてスタックに何度でもプッシュできます。スタックの完全なコンテンツをレンダリングするには、スタックの名前を@stack
ディレクティブに渡します。
<head> <!-- Head Contents --> @stack('scripts')</head>
スタックの先頭にコンテンツをプリペンドする場合は、@prepend
ディレクティブを使用する必要があります。
@push('scripts') This will be second...@endpush // Later... @prepend('scripts') This will be first...@endprepend
サービスインジェクション
@inject
ディレクティブを使用して、Laravelのサービスコンテナからサービスを取得できます。@inject
に渡される最初の引数は、サービスが配置される変数の名前であり、2番目の引数は、解決するサービスのクラス名またはインターフェース名です。
@inject('metrics', 'App\Services\MetricsService') <div> Monthly Revenue: {{ $metrics->monthlyRevenue() }}.</div>
インラインブレードテンプレートのレンダリング
生の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
引数を指定できます。
return Blade::render( 'Hello, {{ $name }}', ['name' => 'Julian Bashir'], deleteCachedView: true);
ブレードフラグメントのレンダリング
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レスポンスに指定されたフラグメントのみを含めるように指定できます。
return view('dashboard', ['users' => $users])->fragment('user-list');
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{ /** * Register any application services. */ public function register(): void { // ... } /** * Bootstrap any application services. */ 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'); ?>
Bladeディレクティブのロジックを更新した後、キャッシュされたBladeビューをすべて削除する必要があります。キャッシュされたBladeビューは、view:clear
Artisanコマンドを使用して削除できます。
カスタムエコーハンドラー
Bladeを使用してオブジェクトを「出力」しようとすると、オブジェクトの__toString
メソッドが呼び出されます。__toString
メソッドは、PHPの組み込み「マジックメソッド」の1つです。ただし、サードパーティライブラリに属するクラスと対話する場合など、特定のクラスの__toString
メソッドを制御できない場合があります。
このような場合、Bladeでは、その特定の種類のオブジェクトのカスタム出力ハンドラーを登録できます。これを実現するには、Bladeのstringable
メソッドを呼び出します。stringable
メソッドはクロージャを受け取ります。このクロージャは、レンダリングを担当するオブジェクトの型を型ヒントする必要があります。通常、stringable
メソッドは、アプリケーションのAppServiceProvider
クラスのboot
メソッド内で呼び出される必要があります。
use Illuminate\Support\Facades\Blade;use Money\Money; /** * Bootstrap any application services. */public function boot(): void{ Blade::stringable(function (Money $money) { return $money->formatTo('en_GB'); });}
カスタム出力ハンドラーを定義したら、Bladeテンプレートでオブジェクトを簡単に出力できます。
Cost: {{ $money }}
カスタムif文
単純なカスタム条件文を定義する場合、カスタムディレクティブのプログラミングは、場合によっては必要以上に複雑になります。そのため、BladeはBlade::if
メソッドを提供しており、これを使用してクロージャを使用してカスタム条件ディレクティブを簡単に定義できます。たとえば、アプリケーションの構成済みのデフォルト「ディスク」をチェックするカスタム条件を定義してみましょう。これは、AppServiceProvider
のboot
メソッドで行うことができます。
use Illuminate\Support\Facades\Blade; /** * Bootstrap any application services. */public function boot(): void{ Blade::if('disk', function (string $value) { return config('filesystems.default') === $value; });}
カスタム条件を定義したら、テンプレート内で使用できます。
@disk('local') <!-- The application is using the local disk... -->@elsedisk('s3') <!-- The application is using the s3 disk... -->@else <!-- The application is using some other disk... -->@enddisk @unlessdisk('local') <!-- The application is not using the local disk... -->@enddisk