【Laravel / Blade】Bladeでの処理はこれで完璧！

# はじめに
こんにちは、エンジニア2年目の嶋田です。
まずは、この記事を開いていただきありがとうございます！

今回は、LaravelのBladeディレクティブについて解説したいと思います。
最後までお付き合いください！

# 目次
- [Bladeとは](#Bladeとは)
- [ディレクティブについて](#ディレクティブについて)
- [分岐](#分岐)
    - [@if](#if)
    - [@unless](#unless)
    - [@empty](#empty)
    - [@isset](#isset)
    - [@switch](#switch)
- [認証ディレクティブ](#認証ディレクティブ)
- [環境ディレクティブ](#環境ディレクティブ)
- [セクションディレクティブ](#セクションディレクティブ)
- [繰り返し](#繰り返し)
    - [@for](#for)
    - [@while](#while)
    - [@foreach](#foreach)
    - [@forelse](#forelse)
- [ループ変数](#ループ変数)
- [レイアウト作成用](#レイアウト作成用)
    - [@section](#section)
    - [@yield](#yield)
    - [@extend](#extend)
    - [@parent](#parent)
    - [@component](#component)
    - [@slot](#slot)
    - [@include](#include)
    - [@each](#each)
- [HTML要素に追加](#HTML要素に追加)
    - [@class](#class)
    - [@style](#style)
    - [@checked](#checed)
    - [@selected](#selected)
    - [@disabled](#disabled)
    - [@readonly](#readonly)
    - [@required](#required)
- [@onceディレクティブ](#onceディレクティブ)
- [生PHP](#生php)
- [最後に](#最後に)

# Bladeとは
Laravelのview作成にはHTMLではなくBladeが使用されます。
ベースとなる書き方はHTMLですが、加えてBlade固有の色々な機能を使用することができます。
Bladeを使うと、テンプレートを継承したり、レイアウトの一部をセクションの一部としてはめ込むことができます。
効率的にレイアウトを作成したいならBladeを使うといいと思います！

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

<a href="https://readouble.com/laravel/10.x/ja/blade.html">上記、公式より引用</a>

# ディレクティブについて
構文のような役割を果たすものでテンプレートに簡単に組み込むことができます。
＠から始まる範囲内で特定の処理を実行することができる記述方法です。
```php
例） 
@include('layouts.footer') 
 
@include('layouts.header', ["banana" => 'yellow'])
```
ディレクティブの利点は動的な部分のコードを比較的少ないコードで記述が可能となることです。

# 分岐
分岐のディレクトリは以下のようにまとめられます。

| ディレクティブ    | 役割                                 |
|-------------------|--------------------------------------|
| `@if(条件)`       | 条件分岐                             |
| `@unless(変数)`   | 条件非成立の時表示                   |
| `@empty(変数)`    | 変数が空の場合表示                   |
| `@isset(変数)`    | 変数が定義済みの場合表示             |
| `@switch`         | 複数の条件に基づいた分岐処理を実行  |

## if
`@if`、`@elseif`、`@else`、`@endif`ディレクティブを使用してif文を作成できます。
これらのディレクティブは、対応するPHPの構文と同じように機能します。
使用例は以下の通りです。
```php
@if (count($records) === 1)
    １レコードあります。
@elseif (count($records) > 1)
    複数レコードあります。
@else
    レコードがありません。
@endif
```
## unless
unlessはifと逆の動きをします。
要は判定がfalseの場合に生じる処理が実行されるということです。
```php
@unless (Auth::check())
    あなたはサインインしていません。
@endunless
```
## empty
emptyは変数内が空の時に実行されるという書き方です。
空文字列, null, 0などの時にtrueとなります。
```php
@empty($records)
    // $recordsは「空」だ…
@endempty
```
## isset
issetはその変数が定義済みでnullではない時に実行されるという書き方です。
定義されていた場合にtrueとなります。
```php
@isset($records)
    // $recordsが定義済みで、NULLではない…
@endisset
```

上記、empty,issetに関しては判定が複雑なので私は<a href="https://qiita.com/shinichi-takii/items/00aed26f96cf6bb3fe62" target="_blank">こちらの早見表</a>をよくみていました。

## switch
switch文は、`@switch`、`@case`、`@break`、`@default`、`@endswitch`ディレクティブを使用して作成できます。
これらのディレクティブは、対応するPHPの構文と同じように機能します。
使用例は以下の通りです。
```php
@switch($i)
    @case(1)
        最初のケース…
        @break

    @case(2)
        ２番めのケース…
        @break

    @default
        デフォルトのケース…
@endswitch
```

# 認証ディレクティブ
こちらは非常に便利です。
`@auth`および`@guest`ディレクティブを使用すると、現在のユーザーが認証済みであるか、ゲストであるかを簡潔に判断できます。使用例は以下の通りです。
```php
@auth
    // ユーザーは認証済み…
@endauth
```

```php
@guest
    // ユーザーは認証されていない…
@endguest
```
# 環境ディレクティブ
`@production`ディレクティブを使用して、アプリケーションが本番環境で実行されているかを確認できます。
```php
@production
    // Production限定コンテンツ…
@endproduction
```
また、`@env`ディレクティブを使用して、アプリケーションが特定の環境で実行されているかどうかを判断できます。
```php
@env('staging')
    // アプリケーションは"staging"で動作している…
@endenv

@env(['staging', 'production'])
    // アプリケーションは"staging"か"production"で動作している…
@endenv
```

# セクションディレクティブ
`@hasSection`ディレクティブを使用して、テンプレート継承セクションにコンテンツがあるかどうかを判断できます。
```html
@hasSection('navigation')
    <div class="pull-right">
        @yield('navigation')
    </div>

    <div class="clearfix"></div>
@endif
```

また、`@sectionMissing`ディレクティブを使用して、セクションにコンテンツがないかどうかを判断できます。
```html
@sectionMissing('navigation')
    <div class="pull-right">
        @include('default-navigation')
    </div>
@endif
```
# 繰り返し
条件文に加えて、BladeはPHPのループ構造を操作するための簡単なディレクティブを提供します。繰り返しますが、これらの各ディレクティブは、対応するPHPと同じように機能します。

:::note warn
今回は記載していませんが、`@continue`および`@break`ディレクティブを使用して、反復をスキップするか、ループを終了することもできます。
:::

繰り返しのディレクトリは以下のようにまとめられます。
| ディレクティブ                     | 役割                            |
|------------------------------------|---------------------------------|
| `@for(初期化 ; 条件; 後処理;)`    | PHPのfor構文に相当するもの     |
| `@foreach(配列, 変数)`             | PHPのforeach構文に相当するもの |
| `@while(条件)`                    | PHPのwhile構文に相当するもの   |

## for
for文として使用できます。指定の回数処理を繰り返す場合に有効です。
```php
@for ($i = 0; $i < 10; $i++)
    現在の値は、{{ $i }}
@endfor
```

## while
while文として使用できます。
指定した条件がtrueの間はループし続けます。
```php
@php 
    $counter = 0;
@endphp
@while ($counter < 10)
    <p>現在の値は {{ $counter }}</p>

    @php
        $counter++;
    @endphp
@endwhile
```

## foreach
foreach文として使用できます。
配列やコレクションの要素分ループします。ループ処理のなかでは最もよく使うと思います。
```php
@foreach ($users as $user)
    <p>このユーザーは：{{ $user->id }}</p>
@endforeach
```

## forelse
foreachと同じく配列やコレクションの要素をループします。
foreachに加え、配列やコレクションに要素が存在しない場合の処理を@emptyディレクティブに記述することができます。
```php
@forelse ($users as $user)
    <li>{{ $user->name }}</li>
@empty
    <p>ユーザーはいません。</p>
@endforelse
```

# ループ変数
Bladeでは、`$loop`という繰り返し処理で使用できる特殊な変数が存在します。
「$loop->取り出したい値」とアクセスすることで、様々なプロパティにアクセスすることが可能となります。
繰り返しのディレクティブに用意されている変数 `$loop`の使い方は以下の通りです。

| ループ変数           | 役割                            |
|----------------------|---------------------------------|
| `$loop->index`       | 現在のインデックス(0~)          |
| `$loop->iteration`   | 現在の繰り返し数(1~)            |
| `$loop->remaining`   | 後何回繰り返すのか              |
| `$loop->count`       | 繰り返しで使っている配列の要素数 |
| `$loop->first`       | 最初の繰り返しかどうか            |
| `$loop->last`        | 最後の繰り返しかどうか            |
| `$loop->depth`       | 繰り返しのネスト数               |
| `$loop->parent`      | ネストしている場合、親の繰り返しループ変数を示す |

`foreach`ループの反復処理中、ループの内部では`$loop`変数を利用できます。
この変数により、現在のループのインデックスや、ループの最初の反復なのか最後の反復なのか、といった便利な情報にアクセスすることができます。
```php
@foreach ($users as $user)
    @if ($loop->first)
        これが最初の繰り返しです。
    @endif

    @if ($loop->last)
        これが最後の繰り返しです。
    @endif

    <p>このユーザーは：{{ $user->id }}</p>
@endforeach
```
ネストしたループ内にいる場合は、`parent`プロパティを介して親ループの`$loop`変数にアクセスできます。
```php
@foreach ($users as $user)
    @foreach ($user->posts as $post)
        @if ($loop->parent->first)
            これは親ループの最初の繰り返しです。
        @endif
    @endforeach
@endforeach
```

ちなみに、ネストとは、あるものの中に、それと同じ形や種類の（一回り小さい）ものが入っている状態や構造のことです！

# レイアウト作成用
レイアウト作成時に必要なディレクティブは以下のようにまとめられます。


| ディレクティブ                   | 役割                            |
|----------------------------------|---------------------------------|
| `@section(名前)`                | 指定した名前でセクションが用意される |
| `@yield(名前)`                   | 配置場所を示すもの                |
| `@extends(Bladeのファイル名)`    | レイアウトの継承設定             |
| `@parent`                        | 親レイアウトのセクションを示す |
| `@component(名前)`               | コンポーネントの組み込み          |
| `@slot(名前)`                    | コンポーネントに動的なコンテンツを挿入する |
| `@include(読み込むテンプレート名, [値の指定])` | サブビューの読み込み     |
| `@each(テンプレート名, 配列, 配列から取り出したデータを入れる変数名)` | 配列などから値を取り出し指定のテンプレートにはめ込んで出力する |

## section
`@section`ディレクティブは、テンプレート内でセクションを定義するために使います。
セクションは、後で他のテンプレートで展開するために内容を保持するものです。
例えば、ウェブページのタイトルやコンテンツ部分を定義するのに役立ちます。

セクションを定義するには、`@section`ディレクティブにセクション名を第一引数に指定し、その中にHTMLやテキストを記述します。使用例は以下の通りです。
```php
@section('title', 'laratimes')

@section('content')
    <div>
        {{ $hoge }}
    </div>
@endsection
```
`title`と `content`という2つのセクションを定義しています。これらのセクションは、後で`@yield`ディレクティブを使用して展開することができます。

## yield
`@yield`ディレクティブは、`@section`ディレクティブで定義されたセクションを展開します。
指定したセクション名を引数として渡すことで、そのセクションの内容を表示できます。
```php
@yield('content')
```
このコードは、`content`セクションの内容を表示します。
また、第二引数を指定することで、セクションが未定義の場合に代替コンテンツを表示することもできます。
```php
@yield('content', View::make('view.id'))
```
上記の例では、`content`セクションが未定義の場合に`view.id`テンプレートを表示します。

## extend
`@extends`ディレクティブは、親レイアウトを子ビューに継承させるために使います。
親レイアウト内で`@yield`ディレクティブで定義したセクションを、子ビュー内で具体的なコンテンツで埋めることができます。
```php
@extends('layouts.app')
```
この例では、`layouts.app`テンプレートを親レイアウトとして継承しています。

## parent

`@parent` ディレクティブは、親レイアウトからセクションの内容を引き継ぐために使用されます。通常、親レイアウトで定義されたセクションを子ビューで上書きすることができますが、一部の場合にはセクションの内容を拡張したり、追加したりしたい場合があります。その際に `@parent` ディレクティブが役立ちます。

例えば、親レイアウトで以下のようにセクションが定義されているとします。

```html
@section('content')
    <div>
        親レイアウトのコンテンツ
    </div>
@endsection
```
子ビューで同じセクションを上書きしつつ、親レイアウトの内容も表示したい場合、`@parent`ディレクティブを使用します。
```html
@extends('layouts.app')

@section('content')
    @parent
    <div>
        子ビューの追加コンテンツ
    </div>
@endsection
```
この例では、`@parent`ディレクティブを使用して親レイアウトのコンテンツを引き継ぎつつ、子ビュー独自のコンテンツを追加しています。最終的に、親レイアウトのコンテンツと子ビューの追加コンテンツが合わさって表示されます。

## include
## each

## componentとslot
`@component`ディレクティブを使用すると、コンポーネントをビューに組み込むことができます。
コンポーネントは再利用可能な部品で、ビュー内で何度も使うことができます。

```php
@component('components.header')
    @slot('header_title')
        ページタイトル
    @endslot

    @slot('header_content')
        <li>項目1</li>
        <li>項目2</li>
    @endslot
@endcomponent
```
上記の例では、`components.header`コンポーネントをビューに組み込んでいます。
`@slot`ディレクティブを使用して、コンポーネント内のスロットに値を設定しています。

細かい解説は<a href="https://laravel-times.com/index.php/2022/01/22/slot_component/" target="_blank">こちら</a>をご覧ください…

## include
この記事の冒頭ディレクティブの書き方の際にも出てきた`@include`です。
`@include`ディレクティブを使用すると、他のテンプレートを読み込むことができます。
第一引数に読み込みたいテンプレートの名前を指定し、必要に応じて第二引数にテンプレートに渡す値を配列で指定できます。
```php
@include('layouts.footer')

@include('layouts.header', ["banana" => 'yellow'])
```
上記の例では、`layouts.footer`と`layouts.header`テンプレートを読み込んでいます。
`["banana" => 'yellow']`のように第二引数に値を渡すことができます。

## each
`@each`ディレクティブを使用すると、配列やコレクションから値を取り出し、指定のテンプレートに組み込んで出力することができます。これを使って、繰り返し表示する要素を簡単に生成できます。
```php
@each('view.name', $jobs, 'job')
```
上記の例では、`view.name`テンプレートを`$jobs`配列から取り出した値を使って繰り返し表示しています。
また、`job`という変数名を指定しています。

# HTML要素に追加
HTML要素に追加するディレクティブは以下のようにまとめられます。
| ディレクティブ                   | 役割                            |
|----------------------------------|---------------------------------|
| `@class`         | 指定したクラス名を条件に基づいて追加する|
| `@style`         | 指定したスタイルを条件に基づいて追加する|
| `@checked`                 | チェックボックスの`checked`属性を条件に基づいて追加する|
| `@selected`                | セレクトボックスのオプションに`selected`属性を条件に基づいて追加する|
| `@disabled`                | HTML要素に`disabled`属性を条件に基づいて追加する。 |
| `@readonly`                | HTML要素に`readonly`属性を条件に基づいて追加する |
| `@required`                | HTML要素に`required`属性を条件に基づいて追加する |

## class
`@class`を使って、条件に応じてクラスを追加できます。
条件付きクラスは、HTML要素にクラス（スタイルやデザインを適用するための指示）を追加する方法です。

たとえば、ウェブページで「ログインしているかどうか」や「エラーが発生しているかどうか」によって、要素のスタイルを変えたい場合があります。以下はその例です。
```html
@php
    $isLoggedIn = false;
    $hasError = true;
@endphp

<span @class([
    'p-4',
    'font-bold' => $isLoggedIn,
    'text-gray-500' => !$isLoggedIn,
    'bg-red' => $hasError,
])></span>
```
このコードでは、`$isLoggedIn`が`true`の場合は`font-bold`クラスを追加し、`$isLoggedIn`が`false`の場合は`text-gray-500`クラスを追加します。また、`$hasError`が`true`の場合は`bg-red`クラスを追加します。
これにより、条件に応じて要素のスタイルを変更できます。

## style
`@style`を使って、条件に応じてスタイルを適用できます。
条件付きスタイルは、HTML要素にインラインのCSSスタイルを追加する方法です。

たとえば、特定の状況で背景色やフォントの太さを変えたい場合があります。以下はその例です。
```html
@php
    $isActive = true;
@endphp

<span @style([
    'background-color: red',
    'font-weight: bold' => $isActive,
])></span>
```
このコードでは、`$isActive`が`true`の場合は背景色を赤にし、`$isActive`が`false`の場合は太字のフォントを適用します。
これにより、条件に応じて要素のスタイルをカスタマイズできます。

## checked
`@checked`ディレクティブを使用すると、指定したHTMLのチェックボックス入力が`checked`であることを条件に基づいて設定できます。

たとえば、フォームでユーザーが事前にチェックしたい場合、次のように使えます。
```html
<input type="checkbox"
        name="active"
        value="active"
        @checked(old('active', $user->active)) />
```
このコードでは、`old`関数とユーザーモデルから取得した値に基づいて、チェックボックスが事前にチェックされるかどうかを制御します。

## selected
`@selected`ディレクティブは、セレクトボックスのオプションに`selected`属性を条件に基づいて追加します。
たとえば、特定のバリューが選択済みであるかどうかを制御したい場合、次のように使用します。
```html
<select name="version">
    @foreach ($product->versions as $version)
        <option value="{{ $version }}" @selected(old('version') == $version)>
            {{ $version }}
        </option>
    @endforeach
</select>
```
このコードでは、`old`関数を使用してフォームの以前のバリューを取得し、選択したバリューと一致するオプションに`selected`属性を追加します。

## disabled
`@disabled`ディレクティブは、指定したHTML要素に`disabled`属性を条件に基づいて追加します。
たとえば、エラーが発生した場合に送信ボタンを無効にする場合、次のように使えます。
```html
<button type="submit" @disabled($errors->isNotEmpty())>Submit</button>
```
このコードでは、`$errors->isNotEmpty()`の条件に基づいて送信ボタンが無効になります。

## readonly
`@readonly`ディレクティブを使用すると、指定したHTML要素に`readonly`属性を条件に基づいて追加します。
たとえば、特定のユーザーが編集できないようにする場合、次のように使えます。
```html
<input type="email"
        name="email"
        value="email@laravel.com"
        @readonly($user->isNotAdmin()) />
```
このコードでは、`$user->isNotAdmin()`の条件に基づいて、メール入力フィールドが読み取り専用になります。

## required
`@required`ディレクティブは、指定したHTML要素に`required`属性を条件に基づいて追加します。
たとえば、特定の条件下でフォームフィールドを必須にする場合、次のように使えます。
```html
<input type="text"
        name="title"
        value="title"
        @required($user->isAdmin()) />
```
このコードでは、`$user->isAdmin()`の条件に基づいて、タイトル入力フィールドが必須になります。

# onceディレクティブ
`@once`ディレクティブを使用すると、テンプレートの特定の部分をレンダリングサイクルごとに1回だけ評価できます。
これは、JavaScriptの特定のコードをページのヘッダーに追加する場合に便利です。
たとえば、ループ内で特定のコンポーネントをレンダリングし、そのコンポーネントが初めてレンダリングされるときにのみJavaScriptをヘッダーに追加したい場合などに役立ちます。
```php
@once
    @push('scripts')
        <script>
            // カスタムJavaScript…
        </script>
    @endpush
@endonce
```
このコードでは、`@once`ディレクティブ内のコードブロックは1回だけ評価され、その後のレンダリングサイクルでは無視されます。これにより、不要な重複を避けてカスタムJavaScriptを追加できます。

`@once`ディレクティブは、通常、`@push`や`@prepend`ディレクティブと組み合わせて使用されます。
便利な`@pushOnce`と`@prependOnce`ディレクティブも用意されており、使用例は以下の通りです。

```php
@pushOnce('scripts')
    <script>
        // カスタムJavaScript…
    </script>
@endPushOnce
```
これで、同じJavaScriptコードが重複して追加されるのを防ぎながら、必要な部分にJavaScriptを追加できます。

# 生PHP
状況によっては、PHPコードをビューに埋め込めると便利ですよね。
`@php`ディレクティブを使用して、テンプレート内でプレーンPHPのブロックを定義し、実行することが可能です。
```php
@php
    $counter = 1;
@endphp
```
また、PHP文を１つ書くだけなら、`@php`ディレクティブ内に含められます。
```php
@php($counter = 1)
```

# 最後に
記事を読んでくださり、ありがとうございます！
長くなってしまいましたが、少しでもお役に立てたら嬉しいです。
Bladeディレクティブは、便利でコードの簡略化につながるところが魅力ですよね。
私自身もまだまだ学びの途中なので、もし何か誤った情報がありましたら、コメントでご指摘いただければ幸いです！