はじめに

Bladeは、Laravelに含まれるシンプルでありながら強力なテンプレートエンジンです。他のPHPテンプレートエンジンとは異なり、Bladeはテンプレート内でプレーンなPHPコードを使用することを制限しません。実際、すべてのBladeテンプレートはプレーンなPHPコードにコンパイルされ、変更されるまでキャッシュされるため、Bladeはアプリケーションに実質的にゼロのオーバーヘッドを追加します。Bladeテンプレートファイルは.blade.phpファイル拡張子を使用し、通常はresources/viewsディレクトリに保存されます。

Bladeビューは、グローバルviewヘルパーを使用してルートやコントローラーから返すことができます。もちろん、ビューに関するドキュメントで述べたように、データはviewヘルパーの第二引数を使用してBladeビューに渡すことができます:

  1. Route::get('/', function () {
  2. return view('greeting', ['name' => 'Finn']);
  3. });

LivewireでBladeを強化する

Bladeテンプレートを次のレベルに引き上げ、簡単に動的インターフェースを構築したいですか?Laravel Livewireをチェックしてください。Livewireを使用すると、通常はReactやVueのようなフロントエンドフレームワークを介してのみ可能な動的機能を強化したBladeコンポーネントを書くことができ、複雑さやクライアントサイドレンダリング、JavaScriptフレームワークのビルドステップなしで、現代的で反応的なフロントエンドを構築するための優れたアプローチを提供します。

データの表示

Bladeビューに渡されたデータは、変数を波括弧で囲むことで表示できます。たとえば、次のルートがあるとします:

  1. Route::get('/', function () {
  2. return view('welcome', ['name' => 'Samantha']);
  3. });
  1. ``````blade
  2. Hello, {{ $name }}.
  3. `

Bladeの{{ }}エコーステートメントは、自動的にPHPのhtmlspecialchars関数を通じて送信され、XSS攻撃を防ぎます。

ビューに渡された変数の内容を表示することに制限されるわけではありません。任意のPHP関数の結果をエコーすることもできます。実際、Bladeエコーステートメント内に任意のPHPコードを記述できます:

  1. The current UNIX timestamp is {{ time() }}.

HTMLエンティティのエンコーディング

デフォルトでは、Blade(およびLaravelのe関数)はHTMLエンティティを二重にエンコードします。二重エンコードを無効にしたい場合は、Blade::withoutDoubleEncodingメソッドをbootメソッドから呼び出します:

  1. <?php
  2. namespace App\Providers;
  3. use Illuminate\Support\Facades\Blade;
  4. use Illuminate\Support\ServiceProvider;
  5. class AppServiceProvider extends ServiceProvider
  6. {
  7. /**
  8. * Bootstrap any application services.
  9. */
  10. public function boot(): void
  11. {
  12. Blade::withoutDoubleEncoding();
  13. }
  14. }

エスケープされていないデータの表示

デフォルトでは、Blade {{ }}ステートメントは自動的にPHPのhtmlspecialchars関数を通じて送信され、XSS攻撃を防ぎます。データをエスケープしたくない場合は、次の構文を使用できます:

  1. Hello, {!! $name !!}.

アプリケーションのユーザーから提供されたコンテンツをエコーする際は、非常に注意してください。ユーザー提供データを表示する際は、通常、エスケープされた二重波括弧構文を使用してXSS攻撃を防ぐべきです。

ブレードテンプレート

JSONのレンダリング

時には、JavaScript変数を初期化するためにJSONとしてレンダリングする意図で配列をビューに渡すことがあります。たとえば:

  1. <script>
  2. var app = <?php echo json_encode($array); ?>;
  3. </script>

ただし、json_encodeを手動で呼び出す代わりに、Illuminate\Support\Js::fromメソッドディレクティブを使用できます。fromメソッドは、PHPのjson_encode関数と同じ引数を受け入れますが、結果のJSONがHTMLの引用符内に適切にエスケープされることを保証します。fromメソッドは、指定されたオブジェクトまたは配列を有効なJavaScriptオブジェクトに変換する文字列JSON.parse JavaScriptステートメントを返します:

  1. <script>
  2. var app = {{ Illuminate\Support\Js::from($array) }};
  3. </script>

Laravelアプリケーションスケルトンの最新バージョンには、Bladeテンプレート内でこの機能に便利にアクセスできるJsファサードが含まれています:

  1. <script>
  2. var app = {{ Js::from($array) }};
  3. </script>

既存の変数をJSONとしてレンダリングするためにJs::fromメソッドのみを使用するべきです。Bladeテンプレートは正規表現に基づいており、ディレクティブに複雑な式を渡そうとすると予期しない失敗を引き起こす可能性があります。

@verbatimディレクティブ

テンプレートの大部分でJavaScript変数を表示している場合、@verbatimディレクティブでHTMLをラップすることで、各Bladeエコーステートメントに@シンボルをプレフィックスする必要がなくなります:

  1. @verbatim
  2. <div class="container">
  3. Hello, {{ name }}.
  4. </div>
  5. @endverbatim

Bladeディレクティブ

テンプレートの継承やデータの表示に加えて、Bladeは条件文やループなどの一般的なPHP制御構造のための便利なショートカットも提供します。これらのショートカットは、PHPの対応物に慣れ親しみながら、PHP制御構造を扱う非常にクリーンで簡潔な方法を提供します。

If文

  1. ``````blade
  2. @if (count($records) === 1)
  3. I have one record!
  4. @elseif (count($records) > 1)
  5. I have multiple records!
  6. @else
  7. I don't have any records!
  8. @endif
  9. `

便利のために、Bladeは@unlessディレクティブも提供します:

  1. @unless (Auth::check())
  2. You are not signed in.
  3. @endunless

すでに説明した条件ディレクティブに加えて、@issetおよび@emptyディレクティブは、それぞれのPHP関数の便利なショートカットとして使用できます:

  1. @isset($records)
  2. // $records is defined and is not null...
  3. @endisset
  4. @empty($records)
  5. // $records is "empty"...
  6. @endempty

認証ディレクティブ

  1. ``````blade
  2. @auth
  3. // The user is authenticated...
  4. @endauth
  5. @guest
  6. // The user is not authenticated...
  7. @endguest
  8. `

必要に応じて、@authおよび@guestディレクティブを使用する際にチェックすべき認証ガードを指定できます:

  1. @auth('admin')
  2. // The user is authenticated...
  3. @endauth
  4. @guest('admin')
  5. // The user is not authenticated...
  6. @endguest

環境ディレクティブ

アプリケーションが本番環境で実行されているかどうかを@productionディレクティブを使用して確認できます:

  1. @production
  2. // Production specific content...
  3. @endproduction

また、@envディレクティブを使用して、アプリケーションが特定の環境で実行されているかどうかを判断できます:

  1. @env('staging')
  2. // The application is running in "staging"...
  3. @endenv
  4. @env(['staging', 'production'])
  5. // The application is running in "staging" or "production"...
  6. @endenv

セクションディレクティブ

  1. ``````blade
  2. @hasSection('navigation')
  3. <div class="pull-right">
  4. @yield('navigation')
  5. </div>
  6. <div class="clearfix"></div>
  7. @endif
  8. `
  1. ``````blade
  2. @sectionMissing('navigation')
  3. <div class="pull-right">
  4. @include('default-navigation')
  5. </div>
  6. @endif
  7. `

セッションディレクティブ

  1. ``````blade
  2. @session('status')
  3. <div class="p-4 bg-green-100">
  4. {{ $value }}
  5. </div>
  6. @endsession
  7. `

スイッチ文

スイッチ文は、@switch@case@break@defaultおよび@endswitchディレクティブを使用して構築できます:

  1. @switch($i)
  2. @case(1)
  3. First case...
  4. @break
  5. @case(2)
  6. Second case...
  7. @break
  8. @default
  9. Default case...
  10. @endswitch

ループ

条件文に加えて、BladeはPHPのループ構造を扱うためのシンプルなディレクティブを提供します。これらのディレクティブは、PHPの対応物と同様に機能します:

  1. @for ($i = 0; $i < 10; $i++)
  2. The current value is {{ $i }}
  3. @endfor
  4. @foreach ($users as $user)
  5. <p>This is user {{ $user->id }}</p>
  6. @endforeach
  7. @forelse ($users as $user)
  8. <li>{{ $user->name }}</li>
  9. @empty
  10. <p>No users</p>
  11. @endforelse
  12. @while (true)
  13. <p>I'm looping forever.</p>
  14. @endwhile
  1. ループを使用する際は、`````@continue`````および`````@break`````ディレクティブを使用して現在の反復をスキップしたり、ループを終了したりできます:
  2. ``````blade
  3. @foreach ($users as $user)
  4. @if ($user->type == 1)
  5. @continue
  6. @endif
  7. <li>{{ $user->name }}</li>
  8. @if ($user->number == 5)
  9. @break
  10. @endif
  11. @endforeach
  12. `

ディレクティブ宣言内に継続またはブレーク条件を含めることもできます:

  1. @foreach ($users as $user)
  2. @continue($user->type == 1)
  3. <li>{{ $user->name }}</li>
  4. @break($user->number == 5)
  5. @endforeach

ループ変数

  1. ``````blade
  2. @foreach ($users as $user)
  3. @if ($loop->first)
  4. This is the first iteration.
  5. @endif
  6. @if ($loop->last)
  7. This is the last iteration.
  8. @endif
  9. <p>This is user {{ $user->id }}</p>
  10. @endforeach
  11. `

ネストされたループにいる場合、$loop変数にparentプロパティを介してアクセスできます:

  1. @foreach ($users as $user)
  2. @foreach ($user->posts as $post)
  3. @if ($loop->parent->first)
  4. This is the first iteration of the parent loop.
  5. @endif
  6. @endforeach
  7. @endforeach
  1. | プロパティ | 説明 |
  2. | --- | --- |
  3. | `````$loop->index````` | 現在のループ反復のインデックス(0から始まる)。 |
  4. | `````$loop->iteration````` | 現在のループ反復(1から始まる)。 |
  5. | `````$loop->remaining````` | ループ内の残りの反復。 |
  6. | `````$loop->count````` | 反復されている配列内のアイテムの総数。 |
  7. | `````$loop->first````` | これがループの最初の反復であるかどうか。 |
  8. | `````$loop->last````` | これがループの最後の反復であるかどうか。 |
  9. | `````$loop->even````` | これがループの偶数反復であるかどうか。 |
  10. | `````$loop->odd````` | これがループの奇数反復であるかどうか。 |
  11. | `````$loop->depth````` | 現在のループのネストレベル。 |
  12. | `````$loop->parent````` | ネストされたループ内にいる場合、親のループ変数。 |
  13. <a name="conditional-classes"></a>
  14. ### 条件付きクラスとスタイル
  15. `````@class`````ディレクティブは、CSSクラス文字列を条件付きでコンパイルします。このディレクティブは、追加したいクラスまたはクラスを含む配列のキーを持つ配列を受け入れ、値はブール式です。配列要素に数値キーがある場合、常にレンダリングされたクラスリストに含まれます:
  16. ``````blade
  17. @php
  18. $isActive = false;
  19. $hasError = true;
  20. @endphp
  21. <span @class([
  22. 'p-4',
  23. 'font-bold' => $isActive,
  24. 'text-gray-500' => ! $isActive,
  25. 'bg-red' => $hasError,
  26. ])></span>
  27. <span class="p-4 text-gray-500 bg-red"></span>
  28. `

同様に、@styleディレクティブを使用して、HTML要素にインラインCSSスタイルを条件付きで追加できます:

  1. @php
  2. $isActive = true;
  3. @endphp
  4. <span @style([
  5. 'background-color: red',
  6. 'font-weight: bold' => $isActive,
  7. ])></span>
  8. <span style="background-color: red; font-weight: bold;"></span>

追加属性

便利のために、@checkedディレクティブを使用して、特定のHTMLチェックボックス入力が「チェックされている」かどうかを簡単に示すことができます。このディレクティブは、提供された条件がtrueに評価される場合、checkedをエコーします:

  1. <input type="checkbox"
  2. name="active"
  3. value="active"
  4. @checked(old('active', $user->active)) />

同様に、@selectedディレクティブを使用して、特定の選択肢が「選択されている」べきかどうかを示すことができます:

  1. <select name="version">
  2. @foreach ($product->versions as $version)
  3. <option value="{{ $version }}" @selected(old('version') == $version)>
  4. {{ $version }}
  5. </option>
  6. @endforeach
  7. </select>

さらに、@disabledディレクティブを使用して、特定の要素が「無効」であるべきかどうかを示すことができます:

  1. <button type="submit" @disabled($errors->isNotEmpty())>Submit</button>

さらに、@readonlyディレクティブを使用して、特定の要素が「読み取り専用」であるべきかどうかを示すことができます:

  1. <input type="email"
  2. name="email"
  3. value=""
  4. @readonly($user->isNotAdmin()) />

さらに、@requiredディレクティブを使用して、特定の要素が「必須」であるべきかどうかを示すことができます:

  1. <input type="text"
  2. name="title"
  3. value="title"
  4. @required($user->isAdmin()) />

サブビューの含め方

@includeディレクティブを使用する自由がありますが、Blade コンポーネントは同様の機能を提供し、データや属性のバインディングなど、@includeディレクティブに対していくつかの利点を提供します。

Bladeの@includeディレクティブを使用すると、別のビューからBladeビューを含めることができます。親ビューで利用可能なすべての変数は、含まれるビューでも利用可能になります:

  1. <div>
  2. @include('shared.errors')
  3. <form>
  4. <!-- Form Contents -->
  5. </form>
  6. </div>

含まれるビューは親ビューで利用可能なすべてのデータを継承しますが、含まれるビューに利用可能にすべき追加データの配列を渡すこともできます:

  1. @include('view.name', ['status' => 'complete'])

存在しないビューを@includeしようとすると、Laravelはエラーをスローします。存在するかもしれないビューを含めたい場合は、@includeIfディレクティブを使用するべきです:

  1. @includeIf('view.name', ['status' => 'complete'])

特定のブール式がtrueまたはfalseに評価される場合にビューを@includeしたい場合は、@includeWhenおよび@includeUnlessディレクティブを使用できます:

  1. @includeWhen($boolean, 'view.name', ['status' => 'complete'])
  2. @includeUnless($boolean, 'view.name', ['status' => 'complete'])

指定されたビューの配列から最初に存在するビューを含めるには、includeFirstディレクティブを使用できます:

  1. @includeFirst(['custom.admin', 'admin'], ['status' => 'complete'])

Bladeビュー内でDIRおよびFILE定数を使用することは避けるべきです。これらはキャッシュされたコンパイル済みビューの場所を参照します。

コレクションのためのビューのレンダリング

Bladeの@eachディレクティブを使用して、ループとインクルードを1行にまとめることができます:

  1. @each('view.name', $jobs, 'job')
  1. `````@each`````ディレクティブに第四引数を渡すこともできます。この引数は、指定された配列が空の場合にレンダリングされるビューを決定します。
  2. ``````blade
  3. @each('view.name', $jobs, 'job', 'view.empty')
  4. `
  1. <a name="the-once-directive"></a>
  2. ### 一度だけのディレクティブ
  3. `````@once`````ディレクティブを使用すると、レンダリングサイクルごとに一度だけ評価されるテンプレートの一部を定義できます。これは、[スタック](#stacks)を使用してページのヘッダーに特定のJavaScriptをプッシュするのに便利です。たとえば、ループ内で特定の[コンポーネント](#components)をレンダリングしている場合、コンポーネントが最初にレンダリングされるときだけJavaScriptをヘッダーにプッシュしたい場合があります:
  4. ``````blade
  5. @once
  6. @push('scripts')
  7. <script>
  8. // Your custom JavaScript...
  9. </script>
  10. @endpush
  11. @endonce
  12. `
  1. ``````blade
  2. @pushOnce('scripts')
  3. <script>
  4. // Your custom JavaScript...
  5. </script>
  6. @endPushOnce
  7. `

生のPHP

特定の状況では、PHPコードをビューに埋め込むことが便利です。Blade @phpディレクティブを使用して、テンプレート内でプレーンなPHPブロックを実行できます:

  1. @php
  2. $counter = 1;
  3. @endphp

また、クラスをインポートするためにPHPを使用するだけの場合は、@useディレクティブを使用できます:

  1. @use('App\Models\Flight')
  1. ``````php
  2. @use('App\Models\Flight', 'FlightModel')
  3. `

コメント

Bladeは、ビュー内でコメントを定義することも許可します。ただし、HTMLコメントとは異なり、Bladeコメントはアプリケーションによって返されるHTMLには含まれません:

  1. {{-- This comment will not be present in the rendered HTML --}}

コンポーネント

コンポーネントとスロットは、セクション、レイアウト、およびインクルードと同様の利点を提供しますが、コンポーネントとスロットのメンタルモデルが理解しやすいと感じる人もいます。コンポーネントを書くには、クラスベースのコンポーネントと匿名コンポーネントの2つのアプローチがあります。

クラスベースのコンポーネントを作成するには、make:component Artisanコマンドを使用します。コンポーネントの使用方法を示すために、シンプルなAlertコンポーネントを作成します。make:componentコマンドは、コンポーネントをapp/View/Componentsディレクトリに配置します:

  1. php artisan make:component Alert
  1. サブディレクトリ内にコンポーネントを作成することもできます:
  2. ``````shell
  3. php artisan make:component Forms/Input
  4. `

上記のコマンドは、Inputコンポーネントをapp/View/Components/Formsディレクトリに作成し、ビューはresources/views/components/formsディレクトリに配置されます。

匿名コンポーネント(クラスなしのBladeテンプレートのみのコンポーネント)を作成したい場合は、--viewフラグをmake:componentコマンドを呼び出すときに使用できます:

  1. 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メソッドでコンポーネントを登録します:

  1. use Illuminate\Support\Facades\Blade;
  2. /**
  3. * Bootstrap your package's services.
  4. */
  5. public function boot(): void
  6. {
  7. Blade::component('package-alert', Alert::class);
  8. }

コンポーネントが登録されると、そのタグエイリアスを使用してレンダリングできます:

  1. <x-package-alert/>

また、componentNamespaceメソッドを使用して、慣例に従ってコンポーネントクラスを自動的にロードすることもできます。たとえば、Nightshadeパッケージには、CalendarおよびColorPickerコンポーネントがPackage\Views\Components名前空間内に存在する場合があります:

  1. use Illuminate\Support\Facades\Blade;
  2. /**
  3. * Bootstrap your package's services.
  4. */
  5. public function boot(): void
  6. {
  7. Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
  8. }

これにより、package-name::構文を使用してベンダー名前空間によるパッケージコンポーネントの使用が可能になります:

  1. <x-nightshade::calendar />
  2. <x-nightshade::color-picker />

Bladeは、コンポーネント名をパスカルケースに変換することによって、このコンポーネントにリンクされたクラスを自動的に検出します。サブディレクトリも「ドット」表記を使用してサポートされています。

コンポーネントのレンダリング

コンポーネントを表示するには、Bladeテンプレートの1つ内でBladeコンポーネントタグを使用できます。Bladeコンポーネントタグは、x-という文字列で始まり、コンポーネントクラスのケバブケース名が続きます:

  1. <x-alert/>
  2. <x-user-profile/>

コンポーネントクラスがapp/View/Componentsディレクトリ内でさらに深くネストされている場合、.文字を使用してディレクトリのネストを示すことができます。たとえば、コンポーネントがapp/View/Components/Inputs/Button.phpにあると仮定すると、次のようにレンダリングできます:

  1. <x-inputs.button/>

コンポーネントを条件付きでレンダリングしたい場合は、コンポーネントクラスにshouldRenderメソッドを定義できます。shouldRenderメソッドがfalseを返す場合、コンポーネントはレンダリングされません:

  1. use Illuminate\Support\Str;
  2. /**
  3. * Whether the component should be rendered
  4. */
  5. public function shouldRender(): bool
  6. {
  7. return Str::length($this->message) > 0;
  8. }

コンポーネントへのデータの渡し方

HTML属性を使用してBladeコンポーネントにデータを渡すことができます。ハードコーディングされたプリミティブ値は、シンプルなHTML属性文字列を使用してコンポーネントに渡すことができます。PHP式や変数は、:文字をプレフィックスとして使用する属性を介してコンポーネントに渡すべきです:

  1. <x-alert type="error" :message="$message"/>

コンポーネントのすべてのデータ属性は、そのクラスコンストラクタで定義する必要があります。コンポーネントのすべてのパブリックプロパティは、自動的にコンポーネントのビューで利用可能になります。コンポーネントのrenderメソッドからビューにデータを渡す必要はありません:

  1. <?php
  2. namespace App\View\Components;
  3. use Illuminate\View\Component;
  4. use Illuminate\View\View;
  5. class Alert extends Component
  6. {
  7. /**
  8. * Create the component instance.
  9. */
  10. public function __construct(
  11. public string $type,
  12. public string $message,
  13. ) {}
  14. /**
  15. * Get the view / contents that represent the component.
  16. */
  17. public function render(): View
  18. {
  19. return view('components.alert');
  20. }
  21. }

コンポーネントがレンダリングされると、変数名をエコーすることでコンポーネントのパブリック変数の内容を表示できます:

  1. <div class="alert alert-{{ $type }}">
  2. {{ $message }}
  3. </div>

ケース

コンポーネントコンストラクタ引数はcamelCaseを使用して指定する必要があり、kebab-caseはHTML属性で引数名を参照する際に使用する必要があります。たとえば、次のコンポーネントコンストラクタを考えてみましょう:

  1. /**
  2. * Create the component instance.
  3. */
  4. public function __construct(
  5. public string $alertType,
  6. ) {}
  1. ``````blade
  2. <x-alert alert-type="danger" />
  3. `

ショート属性構文

コンポーネントに属性を渡す際、ショート属性構文を使用することもできます。これは、属性名が対応する変数名と一致することが多いため、便利です:

  1. {{-- Short attribute syntax... --}}
  2. <x-profile :$userId :$name />
  3. {{-- Is equivalent to... --}}
  4. <x-profile :user-id="$userId" :name="$name" />

属性レンダリングのエスケープ

Alpine.jsなどの一部のJavaScriptフレームワークもコロンプレフィックス属性を使用しているため、::(ダブルコロン)プレフィックスを使用してBladeに属性がPHP式ではないことを通知できます。たとえば、次のコンポーネントを考えてみましょう:

  1. <x-button ::class="{ danger: isDeleting }">
  2. Submit
  3. </x-button>

次のHTMLはBladeによってレンダリングされます:

  1. <button :class="{ danger: isDeleting }">
  2. Submit
  3. </button>

コンポーネントメソッド

コンポーネントテンプレートで利用可能なパブリック変数に加えて、コンポーネント上の任意のパブリックメソッドを呼び出すことができます。たとえば、isSelectedメソッドを持つコンポーネントを想像してみましょう:

  1. /**
  2. * Determine if the given option is the currently selected option.
  3. */
  4. public function isSelected(string $option): bool
  5. {
  6. return $option === $this->selected;
  7. }

このメソッドは、メソッド名に一致する変数を呼び出すことでコンポーネントテンプレートから実行できます:

  1. <option {{ $isSelected($value) ? 'selected' : '' }} value="{{ $value }}">
  2. {{ $label }}
  3. </option>

コンポーネントクラス内の属性とスロットへのアクセス

Bladeコンポーネントは、クラスのレンダーメソッド内でコンポーネント名、属性、およびスロットにアクセスすることも許可します。ただし、このデータにアクセスするには、コンポーネントのrenderメソッドからクロージャを返す必要があります:

  1. use Closure;
  2. /**
  3. * Get the view / contents that represent the component.
  4. */
  5. public function render(): Closure
  6. {
  7. return function () {
  8. return '<div {{ $attributes }}>Components content</div>';
  9. };
  10. }

コンポーネントのrenderメソッドから返されるクロージャは、唯一の引数として$data配列を受け取ることもできます。この配列には、コンポーネントに関する情報を提供するいくつかの要素が含まれます:

  1. return function (array $data) {
  2. // $data['componentName'];
  3. // $data['attributes'];
  4. // $data['slot'];
  5. return '<div {{ $attributes }}>Components content</div>';
  6. }
  1. `````componentName`````は、`````x-`````プレフィックスの後にHTMLタグで使用される名前と等しいです。したがって、`````<x-alert />``````````componentName``````````alert`````になります。`````attributes`````要素には、HTMLタグに存在したすべての属性が含まれます。`````slot`````要素は、コンポーネントのスロットの内容を持つ`````Illuminate\Support\HtmlString`````インスタンスです。
  2. クロージャは文字列を返す必要があります。返された文字列が既存のビューに対応する場合、そのビューがレンダリングされます。そうでない場合、返された文字列はインラインBladeビューとして評価されます。
  3. <a name="additional-dependencies"></a>
  4. #### 追加依存関係
  5. コンポーネントがLaravelの[サービスコンテナ](/read/laravel-11-x/89c648800d1f2464.md)から依存関係を必要とする場合、コンポーネントのデータ属性の前にリストすることで、自動的にコンテナによって注入されます:
  6. ``````php
  7. use App\Services\AlertCreator;
  8. /**
  9. * Create the component instance.
  10. */
  11. public function __construct(
  12. public AlertCreator $creator,
  13. public string $type,
  14. public string $message,
  15. ) {}
  16. `

属性/メソッドの非表示

コンポーネントテンプレートに変数として公開メソッドやプロパティが露出するのを防ぎたい場合は、コンポーネントの$except配列プロパティに追加できます:

  1. <?php
  2. namespace App\View\Components;
  3. use Illuminate\View\Component;
  4. class Alert extends Component
  5. {
  6. /**
  7. * The properties / methods that should not be exposed to the component template.
  8. *
  9. * @var array
  10. */
  11. protected $except = ['type'];
  12. /**
  13. * Create the component instance.
  14. */
  15. public function __construct(
  16. public string $type,
  17. ) {}
  18. }

コンポーネント属性

データ属性をコンポーネントに渡す方法をすでに検討しましたが、コンポーネントが機能するために必要なデータの一部ではない追加のHTML属性(classなど)を指定する必要がある場合もあります。通常、これらの追加属性はコンポーネントテンプレートのルート要素に渡すことを望みます。たとえば、alertコンポーネントを次のようにレンダリングしたいとします:

  1. <x-alert type="error" :message="$message" class="mt-4"/>

コンポーネントのコンストラクタの一部でないすべての属性は、自動的にコンポーネントの「属性バッグ」に追加されます。この属性バッグは、$attributes変数を介してコンポーネントに自動的に提供されます。すべての属性は、この変数をエコーすることでコンポーネント内でレンダリングできます:

  1. <div {{ $attributes }}>
  2. <!-- Component content -->
  3. </div>

コンポーネントタグ内で@envのようなディレクティブを使用することは、現時点ではサポートされていません。たとえば、<x-alert :live="@env('production')"/>はコンパイルされません。

デフォルト/マージされた属性

時には、属性のデフォルト値を指定したり、コンポーネントの属性に追加の値をマージしたりする必要があります。これを実現するために、属性バッグのmergeメソッドを使用できます。このメソッドは、コンポーネントに常に適用されるデフォルトのCSSクラスのセットを定義するのに特に便利です:

  1. <div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
  2. {{ $message }}
  3. </div>

このコンポーネントが次のように利用されると仮定します:

  1. <x-alert type="error" :message="$message" class="mb-4"/>

コンポーネントの最終的なレンダリングHTMLは次のようになります:

  1. <div class="alert alert-error mb-4">
  2. <!-- Contents of the $message variable -->
  3. </div>

条件付きでクラスをマージする

特定の条件がtrueの場合、クラスをマージしたいことがあります。これは、classメソッドを介して実現できます。このメソッドは、追加したいクラスまたはクラスを含む配列を受け入れ、値はブール式です。配列要素に数値キーがある場合、常にレンダリングされたクラスリストに含まれます:

  1. <div {{ $attributes->class(['p-4', 'bg-red' => $hasError]) }}>
  2. {{ $message }}
  3. </div>

コンポーネントに他の属性をマージする必要がある場合、mergeメソッドをclassメソッドにチェーンできます:

  1. <button {{ $attributes->class(['p-4'])->merge(['type' => 'button']) }}>
  2. {{ $slot }}
  3. </button>

他のHTML要素に条件付きでクラスをコンパイルする必要がある場合、マージされた属性を受け取らない要素には、@classディレクティブを使用できます。

非クラス属性のマージ

  1. ``````blade
  2. <button {{ $attributes->merge(['type' => 'button']) }}>
  3. {{ $slot }}
  4. </button>
  5. `

カスタムtypeでボタンコンポーネントをレンダリングするには、コンポーネントを消費するときに指定できます。タイプが指定されていない場合、buttonタイプが使用されます:

  1. <x-button type="submit">
  2. Submit
  3. </x-button>

この例のbuttonコンポーネントのレンダリングHTMLは次のようになります:

  1. <button type="submit">
  2. Submit
  3. </button>
  1. ``````blade
  2. <div {{ $attributes->merge(['data-controller' => $attributes->prepends('profile-controller')]) }}>
  3. {{ $slot }}
  4. </div>
  5. `

属性の取得とフィルタリング

属性をフィルタリングするには、filterメソッドを使用できます。このメソッドはクロージャを受け入れ、属性を属性バッグに保持したい場合はtrueを返す必要があります:

  1. {{ $attributes->filter(fn (string $value, string $key) => $key == 'foo') }}

便利なことに、whereStartsWithメソッドを使用して、指定された文字列で始まるすべての属性を取得できます:

  1. {{ $attributes->whereStartsWith('wire:model') }}

逆に、whereDoesntStartWithメソッドを使用して、指定された文字列で始まるすべての属性を除外できます:

  1. {{ $attributes->whereDoesntStartWith('wire:model') }}
  1. ``````blade
  2. {{ $attributes->whereStartsWith('wire:model')->first() }}
  3. `

コンポーネントに属性が存在するかどうかを確認したい場合は、hasメソッドを使用できます。このメソッドは属性名を唯一の引数として受け取り、属性が存在するかどうかを示すブール値を返します:

  1. @if ($attributes->has('class'))
  2. <div>Class attribute is present</div>
  3. @endif
  1. ``````blade
  2. @if ($attributes->has(['name', 'class']))
  3. <div>All of the attributes are present</div>
  4. @endif
  5. `
  1. ``````blade
  2. @if ($attributes->hasAny(['href', ':href', 'v-bind:href']))
  3. <div>One of the attributes is present</div>
  4. @endif
  5. `

特定の属性の値をgetメソッドを使用して取得できます:

  1. {{ $attributes->get('class') }}

予約語

デフォルトでは、いくつかのキーワードはコンポーネントをレンダリングするためにブレードの内部で使用されるため、予約されています。以下のキーワードは、コンポーネント内で公開プロパティまたはメソッド名として定義できません:

  • data
  • render
  • resolveView
  • shouldRender
  • view
  • withAttributes
  • withName

スロット

コンポーネントに追加のコンテンツを渡す必要がある場合がよくあります。スロットは$slot変数をエコーすることでレンダリングされます。この概念を探るために、alertコンポーネントが次のマークアップを持っていると仮定しましょう:

  1. <!-- /resources/views/components/alert.blade.php -->
  2. <div class="alert alert-danger">
  3. {{ $slot }}
  4. </div>
  1. ``````blade
  2. <x-alert>
  3. <strong>Whoops!</strong> Something went wrong!
  4. </x-alert>
  5. `

時には、コンポーネントが異なる場所で複数の異なるスロットをレンダリングする必要がある場合があります。アラートコンポーネントを修正して「タイトル」スロットの注入を許可しましょう:

  1. <!-- /resources/views/components/alert.blade.php -->
  2. <span class="alert-title">{{ $title }}</span>
  3. <div class="alert alert-danger">
  4. {{ $slot }}
  5. </div>
  1. ``````xml
  2. <x-alert>
  3. <x-slot:title>
  4. Server Error
  5. </x-slot>
  6. <strong>Whoops!</strong> Something went wrong!
  7. </x-alert>
  8. `

スロットのisEmptyメソッドを呼び出して、スロットにコンテンツが含まれているかどうかを確認できます:

  1. <span class="alert-title">{{ $title }}</span>
  2. <div class="alert alert-danger">
  3. @if ($slot->isEmpty())
  4. This is default content if the slot is empty.
  5. @else
  6. {{ $slot }}
  7. @endif
  8. </div>

さらに、hasActualContentメソッドを使用して、スロットにHTMLコメントではない「実際の」コンテンツが含まれているかどうかを判断できます:

  1. @if ($slot->hasActualContent())
  2. The scope has non-comment content.
  3. @endif

スコープ付きスロット

VueなどのJavaScriptフレームワークを使用したことがある場合、「スコープ付きスロット」に慣れているかもしれません。これは、スロット内でコンポーネントのデータやメソッドにアクセスできるようにします。Laravelでは、コンポーネントに公開メソッドやプロパティを定義し、$component変数を介してスロット内でコンポーネントにアクセスすることで、同様の動作を実現できます。この例では、x-alertコンポーネントがそのコンポーネントクラスにformatAlertメソッドを定義していると仮定します:

  1. <x-alert>
  2. <x-slot:title>
  3. {{ $component->formatAlert('Server Error') }}
  4. </x-slot>
  5. <strong>Whoops!</strong> Something went wrong!
  6. </x-alert>

スロット属性

ブレードコンポーネントと同様に、CSSクラス名などの追加の属性をスロットに割り当てることができます:

  1. <x-card class="shadow-sm">
  2. <x-slot:heading class="font-bold">
  3. Heading
  4. </x-slot>
  5. Content
  6. <x-slot:footer class="text-sm">
  7. Footer
  8. </x-slot>
  9. </x-card>

スロット属性と対話するには、スロットの変数のattributesプロパティにアクセスできます。属性との対話方法についての詳細は、コンポーネント属性に関するドキュメントを参照してください:

  1. @props([
  2. 'heading',
  3. 'footer',
  4. ])
  5. <div {{ $attributes->class(['border']) }}>
  6. <h1 {{ $heading->attributes->class(['text-lg']) }}>
  7. {{ $heading }}
  8. </h1>
  9. {{ $slot }}
  10. <footer {{ $footer->attributes->class(['text-gray-700']) }}>
  11. {{ $footer }}
  12. </footer>
  13. </div>

インラインコンポーネントビュー

非常に小さなコンポーネントの場合、コンポーネントクラスとコンポーネントのビューテンプレートの両方を管理するのは面倒に感じるかもしれません。このため、renderメソッドからコンポーネントのマークアップを直接返すことができます:

  1. /**
  2. * Get the view / contents that represent the component.
  3. */
  4. public function render(): string
  5. {
  6. return <<<'blade'
  7. <div class="alert alert-danger">
  8. {{ $slot }}
  9. </div>
  10. blade;
  11. }

インラインビューコンポーネントの生成

インラインビューをレンダリングするコンポーネントを作成するには、inlineオプションを使用してmake:componentコマンドを実行します:

  1. php artisan make:component Alert --inline

動的コンポーネント

時には、コンポーネントをレンダリングする必要がありますが、どのコンポーネントをレンダリングするかは実行時までわからない場合があります。この場合、Laravelの組み込みdynamic-componentコンポーネントを使用して、実行時の値や変数に基づいてコンポーネントをレンダリングできます:

  1. // $componentName = "secondary-button";
  2. <x-dynamic-component :component="$componentName" class="mt-4" />

コンポーネントの手動登録

コンポーネントの手動登録に関する以下のドキュメントは、ビューコンポーネントを含むLaravelパッケージを作成している人に主に適用されます。パッケージを作成していない場合、このコンポーネントドキュメントの部分はあなたに関連しないかもしれません。

アプリケーション用にコンポーネントを書くとき、コンポーネントはapp/View/Componentsディレクトリおよびresources/views/componentsディレクトリ内で自動的に発見されます。

ただし、ブレードコンポーネントを利用するパッケージを構築している場合や、非従来のディレクトリにコンポーネントを配置している場合は、Laravelがコンポーネントを見つける場所を知るために、コンポーネントクラスとそのHTMLタグエイリアスを手動で登録する必要があります。通常、パッケージのサービスプロバイダーのbootメソッドでコンポーネントを登録します:

  1. use Illuminate\Support\Facades\Blade;
  2. use VendorPackage\View\Components\AlertComponent;
  3. /**
  4. * Bootstrap your package's services.
  5. */
  6. public function boot(): void
  7. {
  8. Blade::component('package-alert', AlertComponent::class);
  9. }

コンポーネントが登録されると、そのタグエイリアスを使用してレンダリングできます:

  1. <x-package-alert/>

パッケージコンポーネントの自動ロード

また、componentNamespaceメソッドを使用して、慣例に従ってコンポーネントクラスを自動的にロードすることもできます。たとえば、Nightshadeパッケージには、CalendarおよびColorPickerコンポーネントがPackage\Views\Components名前空間内に存在する場合があります:

  1. use Illuminate\Support\Facades\Blade;
  2. /**
  3. * Bootstrap your package's services.
  4. */
  5. public function boot(): void
  6. {
  7. Blade::componentNamespace('Nightshade\\Views\\Components', 'nightshade');
  8. }

これにより、package-name::構文を使用してベンダー名前空間によるパッケージコンポーネントの使用が可能になります:

  1. <x-nightshade::calendar />
  2. <x-nightshade::color-picker />

Bladeは、コンポーネント名をパスカルケースにすることで、このコンポーネントにリンクされたクラスを自動的に検出します。サブディレクトリも「ドット」表記を使用してサポートされています。

匿名コンポーネント

インラインコンポーネントと同様に、匿名コンポーネントは単一のファイルを介してコンポーネントを管理するメカニズムを提供します。ただし、匿名コンポーネントは単一のビューファイルを利用し、関連するクラスはありません。匿名コンポーネントを定義するには、resources/views/componentsディレクトリ内にブレードテンプレートを配置するだけです。たとえば、resources/views/components/alert.blade.phpでコンポーネントを定義したと仮定すると、次のようにレンダリングできます:

  1. <x-alert/>
  1. ``````blade
  2. <x-inputs.button/>
  3. `

匿名インデックスコンポーネント

時には、コンポーネントが多くのブレードテンプレートで構成されている場合、特定のコンポーネントのテンプレートを単一のディレクトリ内にグループ化したい場合があります。たとえば、次のディレクトリ構造を持つ「アコーディオン」コンポーネントを想像してみてください:

  1. /resources/views/components/accordion.blade.php
  2. /resources/views/components/accordion/item.blade.php

このディレクトリ構造により、アコーディオンコンポーネントとそのアイテムを次のようにレンダリングできます:

  1. <x-accordion>
  2. <x-accordion.item>
  3. ...
  4. </x-accordion.item>
  5. </x-accordion>

ただし、x-accordionを介してアコーディオンコンポーネントをレンダリングするために、「インデックス」アコーディオンコンポーネントテンプレートをresources/views/componentsディレクトリに配置する必要がありました。accordionディレクトリ内の他のアコーディオン関連テンプレートとネストするのではなく。

幸いなことに、ブレードでは、コンポーネントのテンプレートディレクトリ内にindex.blade.phpファイルを配置できます。コンポーネントにindex.blade.phpテンプレートが存在する場合、それはコンポーネントの「ルート」ノードとしてレンダリングされます。したがって、上記の例で示したのと同じブレード構文を引き続き使用できますが、ディレクトリ構造を次のように調整します:

  1. /resources/views/components/accordion/index.blade.php
  2. /resources/views/components/accordion/item.blade.php

データプロパティ/属性

匿名コンポーネントには関連するクラスがないため、どのデータを変数としてコンポーネントに渡すべきか、どの属性をコンポーネントの属性バッグに配置すべきかを区別する方法があるかもしれません。

  1. ``````blade
  2. <!-- /resources/views/components/alert.blade.php -->
  3. @props(['type' => 'info', 'message'])
  4. <div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
  5. {{ $message }}
  6. </div>
  7. `

上記のコンポーネント定義に基づいて、次のようにコンポーネントをレンダリングできます:

  1. <x-alert type="error" :message="$message" class="mb-4"/>

親データへのアクセス

時には、子コンポーネント内で親コンポーネントからデータにアクセスしたい場合があります。この場合、@awareディレクティブを使用できます。たとえば、親<x-menu>と子<x-menu.item>で構成される複雑なメニューコンポーネントを構築していると仮定します:

  1. <x-menu color="purple">
  2. <x-menu.item>...</x-menu.item>
  3. <x-menu.item>...</x-menu.item>
  4. </x-menu>
  1. ``````blade
  2. <!-- /resources/views/components/menu/index.blade.php -->
  3. @props(['color' => 'gray'])
  4. <ul {{ $attributes->merge(['class' => 'bg-'.$color.'-200']) }}>
  5. {{ $slot }}
  6. </ul>
  7. `
  1. ``````blade
  2. <!-- /resources/views/components/menu/item.blade.php -->
  3. @aware(['color' => 'gray'])
  4. <li {{ $attributes->merge(['class' => 'text-'.$color.'-800']) }}>
  5. {{ $slot }}
  6. </li>
  7. `
  1. <a name="anonymous-component-paths"></a>
  2. ### 匿名コンポーネントパス
  3. 前述のように、匿名コンポーネントは通常、`````resources/views/components`````ディレクトリ内にブレードテンプレートを配置することで定義されます。ただし、デフォルトのパスに加えて、他の匿名コンポーネントパスをLaravelに登録したい場合があります。
  4. `````anonymousComponentPath`````メソッドは、匿名コンポーネントの場所への「パス」を最初の引数として受け取り、コンポーネントが配置されるべきオプションの「名前空間」を2番目の引数として受け取ります。通常、このメソッドは、アプリケーションの[サービスプロバイダー](/read/laravel-11-x/934b4900a19307fc.md)の`````boot`````メソッドから呼び出されるべきです:
  5. ``````php
  6. /**
  7. * Bootstrap any application services.
  8. */
  9. public function boot(): void
  10. {
  11. Blade::anonymousComponentPath(__DIR__.'/../components');
  12. }
  13. `

コンポーネントパスが、上記の例のように指定されたプレフィックスなしで登録されると、対応するプレフィックスなしでブレードコンポーネント内でレンダリングできます。たとえば、上記のパスにpanel.blade.phpコンポーネントが存在する場合、次のようにレンダリングできます:

  1. <x-panel />

「名前空間」にプレフィックスを提供することがanonymousComponentPathメソッドの2番目の引数としてできます:

  1. Blade::anonymousComponentPath(__DIR__.'/../components', 'dashboard');

プレフィックスが提供されると、その「名前空間」内のコンポーネントは、コンポーネントがレンダリングされるときにコンポーネント名にコンポーネントの名前空間をプレフィックスとして付けることでレンダリングできます:

  1. <x-dashboard::panel />

レイアウトの構築

コンポーネントを使用したレイアウト

ほとんどのWebアプリケーションは、さまざまなページで同じ一般的なレイアウトを維持します。作成するすべてのビューでレイアウトHTML全体を繰り返す必要がある場合、アプリケーションを維持するのは非常に面倒で困難です。幸いなことに、このレイアウトを単一のブレードコンポーネントとして定義し、アプリケーション全体で使用するのは便利です。

レイアウトコンポーネントの定義

たとえば、「todo」リストアプリケーションを構築していると仮定します。次のようなlayoutコンポーネントを定義するかもしれません:

  1. <!-- resources/views/components/layout.blade.php -->
  2. <html>
  3. <head>
  4. <title>{{ $title ?? 'Todo Manager' }}</title>
  5. </head>
  6. <body>
  7. <h1>Todos</h1>
  8. <hr/>
  9. {{ $slot }}
  10. </body>
  11. </html>

レイアウトコンポーネントの適用

一度layoutコンポーネントが定義されると、コンポーネントを利用するブレードビューを作成できます。この例では、タスクリストを表示するシンプルなビューを定義します:

  1. <!-- resources/views/tasks.blade.php -->
  2. <x-layout>
  3. @foreach ($tasks as $task)
  4. <div>{{ $task }}</div>
  5. @endforeach
  6. </x-layout>

コンポーネントに注入されたコンテンツは、layoutコンポーネント内のデフォルト$slot変数に供給されることを忘れないでください。注目すべき点は、layoutも提供されている場合、$titleスロットを尊重することです。そうでない場合、デフォルトのタイトルが表示されます。タスクリストビューから標準のスロット構文を使用してカスタムタイトルを注入できます。コンポーネントドキュメントで説明したように:

  1. <!-- resources/views/tasks.blade.php -->
  2. <x-layout>
  3. <x-slot:title>
  4. Custom Title
  5. </x-slot>
  6. @foreach ($tasks as $task)
  7. <div>{{ $task }}</div>
  8. @endforeach
  9. </x-layout>

レイアウトとタスクリストビューを定義したので、ルートからtaskビューを返すだけです:

  1. use App\Models\Task;
  2. Route::get('/tasks', function () {
  3. return view('tasks', ['tasks' => Task::all()]);
  4. });

テンプレート継承を使用したレイアウト

レイアウトの定義

レイアウトは「テンプレート継承」を介しても作成できます。これは、コンポーネントの導入前にアプリケーションを構築する主な方法でした。

始めるために、シンプルな例を見てみましょう。まず、ページレイアウトを調べます。ほとんどのWebアプリケーションは、さまざまなページで同じ一般的なレイアウトを維持するため、このレイアウトを単一のブレードビューとして定義するのが便利です:

  1. <!-- resources/views/layouts/app.blade.php -->
  2. <html>
  3. <head>
  4. <title>App Name - @yield('title')</title>
  5. </head>
  6. <body>
  7. @section('sidebar')
  8. This is the master sidebar.
  9. @show
  10. <div class="container">
  11. @yield('content')
  12. </div>
  13. </body>
  14. </html>

このファイルには、典型的なHTMLマークアップが含まれています。ただし、@sectionおよび@yieldディレクティブに注意してください。@sectionディレクティブは、その名前が示すように、コンテンツのセクションを定義し、@yieldディレクティブは、指定されたセクションの内容を表示するために使用されます。

アプリケーションのレイアウトを定義したので、レイアウトを継承する子ページを定義しましょう。

レイアウトの拡張

子ビューを定義する際は、@extendsブレードディレクティブを使用して、子ビューが「継承」すべきレイアウトを指定します。ブレードレイアウトを拡張するビューは、@sectionディレクティブを使用してレイアウトのセクションにコンテンツを注入できます。上記の例で見たように、これらのセクションの内容は@yieldを使用してレイアウトに表示されます:

  1. <!-- resources/views/child.blade.php -->
  2. @extends('layouts.app')
  3. @section('title', 'Page Title')
  4. @section('sidebar')
  5. @parent
  6. <p>This is appended to the master sidebar.</p>
  7. @endsection
  8. @section('content')
  9. <p>This is my body content.</p>
  10. @endsection

この例では、sidebarセクションは、レイアウトのサイドバーにコンテンツを追加するために@parentディレクティブを利用しています(上書きするのではなく)。@parentディレクティブは、ビューがレンダリングされるときにレイアウトの内容に置き換えられます。

前の例とは対照的に、このsidebarセクションは@endsectionで終わり、@showではありません。@endsectionディレクティブはセクションを定義するだけで、@showはセクションを定義し、即座にyieldします。

  1. ``````blade
  2. @yield('content', 'Default content')
  3. `

フォーム

CSRFフィールド

アプリケーションでHTMLフォームを定義するたびに、CSRF保護ミドルウェアがリクエストを検証できるように、フォームに隠しCSRFトークンフィールドを含める必要があります。@csrfブレードディレクティブを使用してトークンフィールドを生成できます:

  1. <form method="POST" action="/profile">
  2. @csrf
  3. ...
  4. </form>

メソッドフィールド

HTMLフォームはPUTPATCH、またはDELETEリクエストを行うことができないため、これらのHTTP動詞を偽装するために隠し_methodフィールドを追加する必要があります。@methodブレードディレクティブがこのフィールドを作成できます:

  1. <form action="/foo/bar" method="POST">
  2. @method('PUT')
  3. ...
  4. </form>

バリデーションエラー

  1. ``````blade
  2. <!-- /resources/views/post/create.blade.php -->
  3. <label for="title">Post Title</label>
  4. <input id="title"
  5. type="text"
  6. class="@error('title') is-invalid @enderror">
  7. @error('title')
  8. <div class="alert alert-danger">{{ $message }}</div>
  9. @enderror
  10. `
  1. ``````blade
  2. <!-- /resources/views/auth.blade.php -->
  3. <label for="email">Email address</label>
  4. <input id="email"
  5. type="email"
  6. class="@error('email') is-invalid @else is-valid @enderror">
  7. `

複数のフォームを含むページでバリデーションエラーメッセージを取得するために、@errorディレクティブに特定のエラーバッグの名前を第二のパラメータとして渡すことができます:

  1. <!-- /resources/views/auth.blade.php -->
  2. <label for="email">Email address</label>
  3. <input id="email"
  4. type="email"
  5. class="@error('email', 'login') is-invalid @enderror">
  6. @error('email', 'login')
  7. <div class="alert alert-danger">{{ $message }}</div>
  8. @enderror

スタック

ブレードでは、名前付きスタックにプッシュして、他のビューやレイアウトのどこかでレンダリングできます。これは、子ビューで必要なJavaScriptライブラリを指定するのに特に便利です:

  1. @push('scripts')
  2. <script src="/example.js"></script>
  3. @endpush

指定されたブール式がtrueに評価される場合に@pushコンテンツをプッシュしたい場合は、@pushIfディレクティブを使用できます:

  1. @pushIf($shouldPush, 'scripts')
  2. <script src="/example.js"></script>
  3. @endPushIf

スタックに必要なだけプッシュできます。スタックの完全な内容をレンダリングするには、@stackディレクティブにスタックの名前を渡します:

  1. <head>
  2. <!-- Head Contents -->
  3. @stack('scripts')
  4. </head>

スタックの先頭にコンテンツを追加したい場合は、@prependディレクティブを使用する必要があります:

  1. @push('scripts')
  2. This will be second...
  3. @endpush
  4. // Later...
  5. @prepend('scripts')
  6. This will be first...
  7. @endprepend

サービスインジェクション

  1. ``````blade
  2. @inject('metrics', 'App\Services\MetricsService')
  3. <div>
  4. Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
  5. </div>
  6. `

インラインブレードテンプレートのレンダリング

時には、生のブレードテンプレート文字列を有効なHTMLに変換する必要があります。これは、renderメソッドを使用してBladeファサードによって提供されます。renderメソッドは、ブレードテンプレート文字列と、テンプレートに提供するオプションのデータ配列を受け取ります:

  1. use Illuminate\Support\Facades\Blade;
  2. return Blade::render('Hello, {{ $name }}', ['name' => 'Julian Bashir']);

Laravelは、インラインブレードテンプレートをstorage/framework/viewsディレクトリに書き込むことによってレンダリングします。ブレードテンプレートをレンダリングした後にLaravelがこれらの一時ファイルを削除するようにしたい場合は、メソッドにdeleteCachedView引数を提供できます:

  1. return Blade::render(
  2. 'Hello, {{ $name }}',
  3. ['name' => 'Julian Bashir'],
  4. deleteCachedView: true
  5. );

ブレードフラグメントのレンダリング

Turboやhtmxなどのフロントエンドフレームワークを使用しているとき、HTTPレスポンス内でブレードテンプレートの一部だけを返す必要がある場合があります。ブレード「フラグメント」を使用すると、まさにそれが可能です。始めるには、ブレードテンプレートの一部を@fragmentおよび@endfragmentディレクティブ内に配置します:

  1. @fragment('user-list')
  2. <ul>
  3. @foreach ($users as $user)
  4. <li>{{ $user->name }}</li>
  5. @endforeach
  6. </ul>
  7. @endfragment

次に、このテンプレートを利用するビューをレンダリングするときに、fragmentメソッドを呼び出して、指定されたフラグメントのみを出力HTTPレスポンスに含めるように指定できます:

  1. return view('dashboard', ['users' => $users])->fragment('user-list');
  1. ``````php
  2. return view('dashboard', ['users' => $users])
  3. ->fragmentIf($request->hasHeader('HX-Request'), 'user-list');
  4. `
  1. ``````php
  2. view('dashboard', ['users' => $users])
  3. ->fragments(['user-list', 'comment-list']);
  4. view('dashboard', ['users' => $users])
  5. ->fragmentsIf(
  6. $request->hasHeader('HX-Request'),
  7. ['user-list', 'comment-list']
  8. );
  9. `

ブレードの拡張

ブレードでは、directiveメソッドを使用して独自のカスタムディレクティブを定義できます。ブレードコンパイラがカスタムディレクティブに遭遇すると、ディレクティブに含まれる式を持つコールバックが提供されます。

次の例では、@datetime($var)ディレクティブを作成し、$varのインスタンスである必要があります。DateTime:

  1. <?php
  2. namespace App\Providers;
  3. use Illuminate\Support\Facades\Blade;
  4. use Illuminate\Support\ServiceProvider;
  5. class AppServiceProvider extends ServiceProvider
  6. {
  7. /**
  8. * Register any application services.
  9. */
  10. public function register(): void
  11. {
  12. // ...
  13. }
  14. /**
  15. * Bootstrap any application services.
  16. */
  17. public function boot(): void
  18. {
  19. Blade::directive('datetime', function (string $expression) {
  20. return "<?php echo ($expression)->format('m/d/Y H:i'); ?>";
  21. });
  22. }
  23. }

この例では、ディレクティブに渡される式にformatメソッドをチェーンします。したがって、このディレクティブによって生成される最終的なPHPは次のようになります:

  1. <?php echo ($var)->format('m/d/Y H:i'); ?>

ブレードディレクティブのロジックを更新した後は、すべてのキャッシュされたブレードビューを削除する必要があります。キャッシュされたブレードビューは、view:clear Artisanコマンドを使用して削除できます。

カスタムエコーハンドラ

ブレードを使用してオブジェクトを「エコー」しようとすると、オブジェクトのtoStringメソッドが呼び出されます。toStringメソッドは、PHPの組み込み「マジックメソッド」の1つです。ただし、時には、特定のクラスのtoStringメソッドを制御できない場合があります。たとえば、やり取りしているクラスがサードパーティライブラリに属している場合です。

このような場合、ブレードでは、その特定のタイプのオブジェクトに対してカスタムエコーハンドラを登録できます。これを実現するには、ブレードのstringableメソッドを呼び出す必要があります。stringableメソッドはクロージャを受け入れます。このクロージャは、レンダリングを担当するオブジェクトのタイプを型ヒントする必要があります。通常、stringableメソッドは、アプリケーションのAppServiceProviderクラスのbootメソッド内で呼び出されるべきです:

  1. use Illuminate\Support\Facades\Blade;
  2. use Money\Money;
  3. /**
  4. * Bootstrap any application services.
  5. */
  6. public function boot(): void
  7. {
  8. Blade::stringable(function (Money $money) {
  9. return $money->formatTo('en_GB');
  10. });
  11. }

カスタムエコーハンドラが定義されると、ブレードテンプレート内でオブジェクトを単にエコーできます:

  1. Cost: {{ $money }}

カスタムif文

カスタムディレクティブをプログラミングすることは、単純なカスタム条件文を定義する際に、時には必要以上に複雑になることがあります。そのため、ブレードは、クロージャを使用してカスタム条件ディレクティブを迅速に定義できるBlade::ifメソッドを提供します。たとえば、アプリケーションの構成されたデフォルト「ディスク」を確認するカスタム条件を定義してみましょう。bootメソッドでこれを行うことができます:

  1. use Illuminate\Support\Facades\Blade;
  2. /**
  3. * Bootstrap any application services.
  4. */
  5. public function boot(): void
  6. {
  7. Blade::if('disk', function (string $value) {
  8. return config('filesystems.default') === $value;
  9. });
  10. }

カスタム条件が定義されると、テンプレート内で使用できます:

  1. @disk('local')
  2. <!-- The application is using the local disk... -->
  3. @elsedisk('s3')
  4. <!-- The application is using the s3 disk... -->
  5. @else
  6. <!-- The application is using some other disk... -->
  7. @enddisk
  8. @unlessdisk('local')
  9. <!-- The application is not using the local disk... -->
  10. @enddisk