LaravelでBladeコンポーネントを使ってページを作成する


# はじめに

Laravel でアプリ作成する機会があったので、Blade コンポーネントなるものを使ってみた。

あとでまた調べたくなるかもしれないので、使い方とかサンプルコードを残しておく。

# Blade コンポーネントって何？

Laravel に標準で組み込まれているテンプレートエンジンとして、Blade という機能がある。（Java の Spring だと Thymeleaf に該当する機能かな？）

拡張子として`.blade.php`が使われ、プロジェクト内の`resources/view`配下に置かれた`.blade.php`ファイルは Blade テンプレートとして自動的に認識される。

Blade テンプレートを使うことで、複数ページに共通する部分を切り分けて定義して`@extends`等で呼び出すことができ、コードの冗長化を防いでメンテナンスしやすくしてくれる。

Blade コンポーネントの場合は、`<x-xxxxx />`という形でコンポーネント名を指定して呼び出す。

動的に埋め込みたい値はクラスのコンストラクタで渡せるので、いろいろ柔軟に対応できる。

# 使ってみる

めちゃくちゃざっくり特徴は掴めたので、実際に使ってみる。

## 前提

今回検証に使っているのは、下記の環境です。

バージョン古いですが、基本的なコマンドや挙動は変わらないはずなのでご容赦。

プロジェクトの作成とかは説明省略。

- PHP 7.4.0
- Laravel 7.12.0

あと、軽くスタイルを当てたいので、`Tailwind CSS`という便利な CSS フレームワークの CDN を適用する。

やり方は簡単で、HTML の head タグ内に以下の 1 行を埋め込むだけ。

```html
<script src="https://cdn.tailwindcss.com"></script>
```

## Blade コンポーネントの使い方

実際に動作を確認しつつ、コンポーネント作成から使用までの流れを体験してみる。

### コンポーネントの作成

```bash
php artisan make:component コンポーネント名
```

Laravel プロジェクトのルートディレクトリでこのコマンドを実行すると、下記 2 ファイルが作成される。

- `app/View/Components/Xxxxx.php`
- `resources/views/components/xxxxx.blade.php`

サブディレクトリを使って階層を分けて管理したい場合、次のような感じでコマンドを実行する。

```bash
php artisan make:component Sample/Sample
```

そうすると、こんな感じで 2 ファイルできる。

- `app/View/Components/Sample/Sample.php`
- `resources/views/components/sample/sample.blade.php`

それぞれの中身はこんな感じ。

```php:app/View/Components/Sample/Sample.php
<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Sample extends Component
{
    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\View\View|string
     */
    public function render()
    {
        return view('components.sample');
    }
}

```

```html:resources/views/components/sample/sample.blade.php
<div>
  <!-- It is not the man who has too little, but the man who craves more, that is poor. - Seneca -->
</div>
```

### ルーティング追加と view ファイル作成

`routes/web.php`にサンプルページのルーティングを追加

```php:routes/web.php
Route::get('/sample', function () { return view('sample'); });
```

`resources/views/sample.blade.php`を作成

```html:resources/views/sample.blade.php
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://cdn.tailwindcss.com"></script>
  </head>
  <body>
    <div class="container">
      <x-sample.sample />
    </div>
  </body>
</html>
```

`<x-sample.sample />`の部分で、先ほど作成したコンポーネント`resources/views/components/sample/sample.blade.php`が呼び出される。

サブディレクトリ内のコンポーネントを呼び出す場合、`ディレクトリ名.コンポーネント名`という指定の仕方になる。

`resources/views/components/sample/sample.blade.php`の内容をデフォルトから書き換えておく。

```html:resources/views/components/sample/sample.blade.php
<div class="p-5 m-5 border rounded-md bg-green-200 border-green-700 shadow-xl">
  This is Sample.
</div>
```

### アクセスして表示確認

サーバーを起動し、私の場合は 80 ポートで作業していたので`localhost/sample`にアクセスしてみる。

![Bladeコンポーネント1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418680/a9e580b2-216b-508d-a99f-4f89857e108b.jpeg)

表示できた！

### 値を渡す

コンポーネント呼び出し元から PHP 変数などを渡す場合、コンポーネント作成時にできたクラスのフィールドとコンストラクタに追加する。

`app/View/Components/Sample/Sample.php`

```php:app/View/Components/Sample/Sample.php
<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Sample extends Component
{
    public $message;
    public $isAlert;
    /**
     * Create a new component instance.
     *
     * @return void
     */
    public function __construct($message,$isAlert)
    {
        $this->message = $message;
        $this->isAlert = filter_var($isAlert, FILTER_VALIDATE_BOOLEAN);
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\View\View|string
     */
    public function render()
    {
        return view('components.sample');
    }
}
```

表示するテキストを渡す`$message`と、アラートか否かの Boolean を渡す`$isAlert`を定義した。

呼び出し元のファイルにも変更を加え、値を渡すようにする。

```html:resources/views/sample.blade.php
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://cdn.tailwindcss.com"></script>
  </head>
  <body>
    <div class="container">
      <x-sample.sample message="ログイン成功しました！" :isAlert="false" />
      <x-sample.sample message="ログイン失敗しました..." :isAlert="true" />
    </div>
  </body>
</html>
```

渡された値によって出力内容を変えられるように、コンポーネントファイルにも変更を加える。

```html:resources/views/components/sample/sample.blade.php
<div
  class="p-5 m-5 border rounded-md bg-{{$isAlert ? 'red' : 'green'}}-200 border-{{$isAlert ? 'red' : 'green'}}-700 shadow-xl"
>
  {{$message}}
</div>
```

アラートだったら赤、そうでなければ緑で表示して、メッセージも受け取った値が出るように変更した。

### 動作確認

もう一度、`localhost/sample`にアクセスしてみる。

![Bladeコンポーネント2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418680/44693ef2-2f93-0d36-48d9-ebcdb31c7a53.jpeg)

いい感じに値を渡すことができた！

# おわりに

Blade コンポーネントとても便利！

Laravel だと React みたいなコンポーネント管理はできないものと思い込んでたけど、ファイルをコンポーネント単位で切り分けられるのでメンテナンス性も高い。

PHP かじった程度の自分としても、Laravel や WordPress はでかい OSS プロジェクトだという認識があるし、最新の 11 とかになるとかなり便利な機能も増えていると思うので、時間みつけて触ってみようと思う。

ひとまず Blade コンポーネントについて理解が深まったので、終わり！

# 参考

- [Laravel 7.x - Blade Templates](https://laravel.com/docs/7.x/blade)
- [Tailwind CSS](https://tailwindcss.com/)