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']);
});
Laravel 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の {{ }}
ステートメントは自動的にPHPの htmlspecialchars
関数を通過してXSS攻撃を防ぎます。データをエスケープしたくない場合は、次の構文を使用できます:
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ステートメントの文字列を返します:
最新のLaravelアプリケーションスケルトンには、Bladeテンプレート内でこの機能に便利にアクセスできるJs
ファサードが含まれています:
<script>
var app = {{ Js::from($array) }};
</script>
既存の変数をJSONとしてレンダリングする場合は、Js::from
メソッドのみを使用する必要があります。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
、@case
、@break
、@default
、@endswitch
ディレクティブを使用して、スイッチ文を構築できます:
@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"
value="email@laravel.com"
@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 回だけ評価できます。これは、stacks を使用してページのヘッダーに特定の JavaScript ピースをプッシュする場合に便利です。たとえば、ループ内で特定の component をレンダリングしている場合、コンポーネントが最初にレンダリングされるときだけ JavaScript をヘッダーにプッシュしたい場合があります:
@once
@push('scripts')
<script>
// Your custom JavaScript...
</script>
@endpush
@endonce
@once
ディレクティブはしばしば @push
または @prepend
ディレクティブと組み合わせて使用されるため、便宜上 @pushOnce
および @prependOnce
ディレクティブが利用可能です。
@pushOnce('scripts')
<script>
// Your custom JavaScript...
</script>
@endPushOnce
Raw PHP
いくつかの状況では、ビューに PHP コードを埋め込むことが役立ちます。Blade の @php
ディレクティブを使用して、テンプレート内でプレーンな PHP ブロックを実行できます:
@php
$counter = 1;
@endphp
または、クラスをインポートするだけの場合は、@use
ディレクティブを使用できます:
@use('App\Models\Flight')
インポートされたクラスにエイリアスを付けるために、@use
ディレクティブに第二引数を指定することもできます:
@use('App\Models\Flight', 'FlightModel')
Comments
Blade では、ビュー内でコメントを定義することもできます。ただし、HTML コメントとは異なり、Blade コメントはアプリケーションが返す HTML には含まれません:
{{-- This comment will not be present in the rendered HTML --}}
Components
コンポーネントとスロットは、セクション、レイアウト、およびインクルードと同様の利点を提供しますが、コンポーネントとスロットのメンタルモデルが理解しやすいと感じる人もいます。コンポーネントを記述する方法には、クラスベースのコンポーネントと匿名コンポーネントの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 テンプレートの中で Blade コンポーネントタグを使用できます。Blade コンポーネントタグは、コンポーネントクラスの kebab case 名の後に 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;
}
コンポーネントへのデータの渡し方
Blade コンポーネントにデータを渡すには、HTML 属性を使用します。ハードコードされたプリミティブ値は、単純な 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" />
属性のエスケープレンダリング
一部の JavaScript フレームワーク(Alpine.js など)もコロンをプレフィックスとする属性を使用するため、Blade にその属性が PHP の式でないことを伝えるために、ダブルコロン (::
) プレフィックスを使用することができます。たとえば、次のようなコンポーネントがある場合:
<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
メソッドからクロージャを返す必要があります。このクロージャは、唯一の引数として$data
配列を受け取ります。この配列には、コンポーネントに関する情報を提供するいくつかの要素が含まれています:
use Closure;
/**
* Get the view / contents that represent the component.
*/
public function render(): Closure
{
return function (array $data) {
// $data['componentName'];
// $data['attributes'];
// $data['slot'];
return '<div>Components content</div>';
};
}
componentName
は、x-
プレフィックスの後にHTMLタグで使用された名前と等しいです。したがって、<x-alert />
のcomponentName
はalert
になります。attributes
要素には、HTMLタグに存在したすべての属性が含まれます。slot
要素は、コンポーネントのスロットの内容を持つIlluminate\Support\HtmlString
インスタンスです。
クロージャは文字列を返す必要があります。返された文字列が既存のビューに対応する場合、そのビューがレンダリングされます。それ以外の場合、返された文字列はインラインBladeビューとして評価されます。
追加の依存関係
コンポーネントがLaravelのサービスコンテナから依存関係を必要とする場合、コンポーネントのデータ属性の前にそれらをリストアップすることができます。これにより、コンテナによって自動的にインジェクションされます:
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
などのディレクティブをコンポーネントタグ内で使用することは現時点ではサポートされていません。例えば、<x-alert :live="@env('production')"/>
はコンパイルされません。
デフォルト / マージされた属性
時には、属性のデフォルト値を指定したり、コンポーネントの一部の属性に追加の値をマージしたりする必要があることがあります。これを実現するために、属性バッグの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
ディレクティブを使用できます。
クラス以外の属性のマージ
class
属性でない属性をマージする場合、merge
メソッドに提供される値は属性の「デフォルト」値と見なされます。ただし、class
属性とは異なり、これらの属性は注入された属性値とマージされません。代わりに上書きされます。たとえば、button
コンポーネントの実装は次のようになります:
<button {{ $attributes->merge(['type' => 'button']) }}>
{{ $slot }}
</button>
ボタンコンポーネントをカスタムのtype
でレンダリングするには、コンポーネントを使用する際に指定することができます。タイプが指定されていない場合は、button
タイプが使用されます:
<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>
コンポーネントにコンテンツを注入することで、slot
にコンテンツを渡すことができます:
<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>
さらに、スロットに HTML コメント以外の "実際の" コンテンツが含まれているかどうかを判断するために、 hasActualContent
メソッドを使用することができます:
@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 コンポーネントと同様に、スロットに追加の 属性 を割り当てることができます:
<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テンプレートで構成されている場合、指定されたコンポーネントのテンプレートを単一のディレクトリ内にグループ化したいと思うことがあります。たとえば、次のディレクトリ構造を持つ「アコーディオン」コンポーネントを想像してみてください:
/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」アコーディオンコンポーネントテンプレートを他のアコーディオン関連テンプレートと一緒にaccordion
ディレクトリにネストするのではなく、resources/views/components
ディレクトリに配置する必要がありました。
幸いにも、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>
与えられたコンポーネント定義を上記のようにレンダリングすることができます。
<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属性を介して明示的に親コンポーネントに渡されていない親データにアクセスすることはできません。@aware
ディレクティブでは、親コンポーネントに明示的に渡されていないデフォルトの @props
値にアクセスすることはできません。
匿名コンポーネントパス
以前に議論したように、匿名コンポーネントは通常、Bladeテンプレートを resources/views/components
ディレクトリに配置することで定義されます。ただし、デフォルトのパスに加えて、Laravelに他の匿名コンポーネントパスを登録したい場合があります。
anonymousComponentPath
メソッドは、最初の引数として匿名コンポーネントの場所への "パス"、2番目の引数としてコンポーネントを配置するオプションの "名前空間" を受け入れます。通常、このメソッドは、アプリケーションの サービスプロバイダ の boot
メソッドから呼び出すべきです:
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Blade::anonymousComponentPath(__DIR__.'/../components');
}
上記の例のように、指定されたプレフィックスなしでコンポーネントパスが登録されると、Bladeコンポーネント内で対応するプレフィックスなしでレンダリングされることがあります。たとえば、上記で登録されたパスに panel.blade.php
コンポーネントが存在する場合、次のようにレンダリングされるかもしれません:
<x-panel />
anonymousComponentPath
メソッドの第二引数として "namespaces" プレフィックスを指定できます:
Blade::anonymousComponentPath(DIR.'/../components', 'dashboard');
プレフィックスが指定された場合、その "namespace" 内のコンポーネントは、コンポーネントがレンダリングされる際に、コンポーネント名にプレフィックスを付けてレンダリングすることができます:
<x-dashboard::panel />
レイアウトの構築
コンポーネントを使用したレイアウト
ほとんどの 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)
{{ $task }}
@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)
{{ $task }}
@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ディレクティブを使用して、子ビューがどのレイアウトを "継承" するかを指定します。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されるセクションが未定義の場合にレンダリングされます:
@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
ディレクティブの第二パラメータとして特定のエラーバッグの名前を渡すことができます:
<!-- /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 テンプレートのレンダリング
時々、生の 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
);
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
メソッドを呼び出して、指定されたフラグメントのみが送信されるように指定できます:
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)
ディレクティブを作成し、与えられた $var
(DateTime
のインスタンスである必要があります)をフォーマットします。
<?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 を使用してオブジェクトを "echo" しようとすると、オブジェクトの __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
メソッドを提供しています。例えば、アプリケーションの設定されたデフォルトの「disk」をチェックするカスタム条件を定義しましょう。これは、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