Laravel + livewireで誕生日から年齢を自動計算するサンプル

さてさて、このブログの記事を書くために常日頃からネット上からいろいろな情報を集めるようにしているのですが、それでもはやり限界があって全ての新しい情報を取得することは難しいものです。

先日も私のクライアントさんとお話させていただいた際に教えていただいたのですが、なんでもlivewireというLaravel用のコンポーネント・システムが公開されているとのことでした。(いつも有益な情報ありがとうございます😊✨)

早速調べてみたところ、livewireのコンセプトは「最近のJavaScriptはちょっとしたことするだけなのに、複雑な作業が必要。もう、そういうのやめよう!」といったものでした。

たしかに、最近のLaravelJavaScriptのコードを変更する際には、npmを使って変更をwatchして、(自動とはいえ)ビルドの完了を毎回待って、やっとできたと思ったらまた変更が必要で・・・再読込が追いつかない・・・(以下繰り返し)

みたいな状況になっているので、livewireのコンセプトはとても賛成できるものでした。(私自身もビルドはnpmのパッケージのみで独自のコードは直接Bladeに書き込む形式をとっています)

そこで!
今回は、そんな気になるlivewireの使い方を分かりやすくまとめてみることにしました。

ぜひ皆さんのお役に立てると嬉しいです😊✨

開発環境: Laravel 5.8

livewireの仕組み

livewireといっても、composerでインストールできるパッケージの1つでLaravelが採用しているテンプレート・エンジンのBladeを利用してコンポーネントを描画します。

そして、コンポーネントの内容をリアルタイムに変更(例えば、テキストの表示/非表示の切り替え)できるのですが、これはAjaxを通してPHP側からHTML(DOM)を取得して自動で行ってくれます。

また、そのリアルタイム変更に必要なJavaScriptコードはlivewireのパッケージがすでに用意してくれているので独自にコードを書く必要はありません。

やりたいこと

今回は、以下のように誕生日(年・月・日)を入力すると自動的に年齢を計算して表示してくれるコンポーネント「birthday」を作ってみます。

※ なお、「日」のセレクトボックスは各月に合わせて28日〜31日が自動的に変更されるようにし、さらに「うるう年」の場合は2月29日も表示するようにします。

では、実際にlivewireをインストールしてコードを書いていきましょう!

livewireをインストールする

先ほども言いましたがlivewirecomposerにパッケージが用意されていますので、以下のコマンドだけでインストールが完了します。

composer require calebporzio/livewire

livewireに必要なファイルを作成する

ファイルの作成はlivewireが用意してくれているartisanコマンドで作成することができます。

以下のコマンドを実行してください。

php artisan make:livewire birthday

すると、以下2つのファイルが自動的に作成されます。

  • /app/Http/Livewire/Birthday.php ・・・ コンポーネントを管理するPHPクラス
  • /resources/views/livewire/birthday.blade.php ・・・ コンポーネントのテンプレート

コンポーネントに必要なコードを追加する

先ほど作成した2つのファイルに必要なコードを追加していきます。
それぞれみていきましょう。

PHPクラス

中身はlivewireが用意しているComponetクラスを拡張する形になっています。中身を以下のように変更してください。

<?php

namespace App\Http\Livewire;

use Carbon\Carbon;
use Livewire\Component;

class Birthday extends Component
{
    // ここの変数がテンプレート内で変数として使える
    public $year = 0;
    public $month = 0;
    public $day = 0;
    public $age = -1;
    public $last_day_of_month = 0;

    // 準備が完了したら実行される
    public function mount($year = 0, $month = 0, $day = 0) {

        $this->year = $year;
        $this->month = $month;
        $this->day = $day;
        $this->onChange();

    }

    // 入力ボックスに変更があった場合に呼ばれる
    public function onChange()
    {
        $year = intval($this->year);
        $month = intval($this->month);
        $day = intval($this->day);

        // 該当月の日(28〜31日)を計算
        if($year > 0 && $month > 0) {

            $this->last_day_of_month = Carbon::create($this->year, $this->month)->endOfMonth()->day;

        }

        // 年齢を計算
        if(checkdate($month, $day, $year)) {

            $this->age = Carbon::createFromDate($this->year, $this->month, $this->day)->age;

        } else {

            $this->age = -1;

        }
    }

    public function render()
    {
        return view('livewire.birthday');
    }
}

まず、ここで重要なのが「publicメンバ変数」です。
今回のコードでは5つの変数を宣言していますが、これらは自動的に/resources/views/livewire/birthday.blade.phpの中で、通常のBladeのように変数として利用することができます。

{{ $year }}
{{ $month }}
{{ $day }}
{{ $age }}
{{ $last_day_of_month }}

続いてmount()ですが、これはコンポーネントの準備ができた時点で呼ばれるメソッドです。

コンポーネントの呼び出しは以下のようになりますが、このmount()に引数を用意しているとその次のようにデフォルト値を指定することも可能になります。

@livewire('birthday')

デフォルト値あり↓↓↓

@livewire('birthday', 2000, 12, 31)

また、onChange()は(年・月・日)が変更されたときに実行されるメソッドですが、この中では以下2つのことを行っています。

  • 「日」のセレクトボックスの内容を変更(28日〜31日)
  • 年齢を計算

Bladeテンプレート

では、コンポーネントのテンプレート/resources/views/livewire/birthday.blade.phpにもコードを追加していきましょう。

<div>

    <!-- 年 -->
    <select name="birth-year" wire:model="year" wire:change="onChange">
        <option></option>
        @for($i = 1900 ; $i <= date('Y') ; $i++)
        <option value="{{ $i }}">{{ $i }}年</option>
        @endfor
    </select>

    <!-- 月 -->
    <select name="birth-month" wire:model="month" wire:change="onChange">
        <option></option>
        @for($i = 1 ; $i <= 12 ; $i++)
        <option value="{{ $i }}">{{ $i }}月</option>
        @endfor
    </select>

    <!-- 日 -->
    <select name="birth-day" wire:model="day" wire:change="onChange">
        <option></option>
        @for($i = 1 ; $i <= $last_day_of_month ; $i++)
        <option value="{{ $i }}">{{ $i }}日</option>
        @endfor
    </select>

    <!-- 年齢 -->
    @if($age > -1)
        &nbsp;/&nbsp;{{ $age }} 才
    @endif

</div>

この中でやっていることは、(年・月・日)のセレクトボックスと年齢を表示しているだけですが、重要なのは「日」のセレクトボックスにある$last_day_of_monthの部分です。なぜなら、この数字が条件によって28日〜31日に変更されることになるからです。

また、年齢は-1(初期値)の場合は表示をしないようにしています。

コンポーネントを表示させる

では、ここまでで作成したコンポーネントをLaravelのページに表示させてみます。

とはいっても、livewire専用のディレクティブが用意されているのでビュー内で以下のようにするだけです。

<html>
<body>
    <div>
        @livewire('birthday')
    </div>

    @livewireAssets
</body>
</html>

この中で、@livewire()がコンポーネントの呼び出しで、@livewireAssetsAjaxなどに必要なJavaScriptコードを描画するディレクティブになります。

テストしてみる(動画あり)

では、今回作成したlivewireコンポーネントを実行してみましょう!(2000年はうるう年なので、2月が29日まであることに注目して見てください)

うまくいきました!

お疲れ様でした😊✨

おわりに

ということで、今回ははじめてlivewireに挑戦してみましたが、使ってみた感想としては、「直感的で使いやすい!」でした。

というのも、livewireと言ってもテンプレートはBladeと同じですし、PHP側も通常よくあるクラスのパターンと同じなので、Laravelを使ってる方でしたらすぐ使えるようになると思います。JavaScriptコードもすでに用意してくれていますしね😚

ただ、一点だけこれからの開発に期待したい部分があって、それが「バインディングデータをJavaScript側から取得しやすくしてほしい」というものでした。

というのも、livewireコンポーネント内の値を取得するには、document.getElementByIddocument.querySelectorを使って取得する必要があるようなのですが、コンポーネントを同じページで複数使う場合は少しややこしくなってしまいます。

そのため、例えば以下のようにrefidを指定できるようにして・・・

<!-- 注:このやり方は存在しません -->

@livewire('birthday')
    @ref('my-birthday')
@endlivewire

<lw:birthday id="partners-birthday"></lw:birthday>

Vueのように値が直接アクセスできればより便利かなと感じました。

// 注:このやり方は存在しません
livewire.$refs['my-birthday'].year;

といっても、現時点でGitHubのスターが781となっていて相当注目を集めているので、きっとこれから進化していくと思います。ということで、私もこれからのlivewireに注目したいと思います。(時間が出来たらpull requestとかしてみようかな)

ぜひ、皆さんもlivewireに挑戦してみてくださいね。

ではでは〜!

この記事が役立ちましたらシェアお願いします😊✨