入力値に関する処理をまとめられるフォームクラス
ここで、フォームに関するロジックの再利用を考えます。
フォームクラスはFormクラスを継承
例えば、カクテル情報を管理する場合、図4のカクテル情報の追加画面だけでなく、編集画面による更新処理も必要です。とはいえ、その画面の入力データは同じであり、バリデーションなどの処理もほぼ同じです。そのため処理コードを再利用すると、効率がよいです。
そこで便利なのが、Livewireのフォームクラスです。このフォームクラスを作成するコマンドは、次の通りです。
php artisan livewire:form フォームクラス名
カクテル情報のフォームクラス名をCocktailFormとして、次のコマンドを実行します。
php artisan livewire:form CocktailForm
すると、app/Livewire/Forms/CocktailForm.phpファイルが自動生成されています。そのクラス内に、リスト4の(1)~(4)の入力値を格納するプロパティと、(6)~(7)のバリデーションとデータベースへの保存処理を移管すると、リスト5のようになります。
class CocktailForm extends Form // (1)
{
#[Validate("required")] // (2)
public string $cocktailName; // (2)
#[Validate("required|gte:100")] // (2)
public int $cocktailPrice; // (2)
public function store() // (3)
{
$this->validate(); // (4)
$cocktail = new Cocktail(); // (4)
$cocktail->name = $this->cocktailName; // (4)
$cocktail->price = $this->cocktailPrice; // (4)
$cocktail->save(); // (4)
}
}
リスト5の(1)のように、フォームクラスは、Formクラスを継承して作ります。もっとも、このコードは、livewire:formコマンドによって自動的に記述されています。
そして、そのフォームクラス内に、入力値に関するプロパティを定義します。リスト5では(2)が該当し、これはリスト4の(1)~(4)をそのまま転記したものとなっています。
さらに、保存処理なども記述でき、リスト5では(3)のstore()メソッドを定義し、その中に(4)のように記述しています。このコードは、リスト4の(6)と(7)のコードをそのまま転記しています。
コンポーネントクラスではフォームクラスとプロパティとする
こうしたフォームクラスを作成した場合、コンポーネントクラスでは、リスト6の(1)のようにフォームクラスをプロパティとします。add()メソッド内は(2)のように、フォームクラスのstore()メソッドを実行するだけとなります。
class CocktailAdd extends Component
{
public CocktailForm $cocktailForm; // (1)
public function add()
{
$this->cocktailForm->store(); // (2)
return redirect()->to("/cocktailList");
}
:
}
ただし、コンポーネントビューファイルでの値の表示では、プロパティがフォームクラスになったのに合わせて、cocktailForm経由となる点には注意してください(リスト7)。
:
<input type="text" wire:model="cocktailForm.cocktailName" id="cocktailName">
<div>@error("cocktailForm.cocktailName") {{$message}} @enderror</div><br>
:
編集画面の表示はmount()でフォームクラスにデータを渡す
このフォームクラスを利用して編集画面を表示させる場合、リスト8のようになります。
class CocktailForm extends Form
{
public ?Cocktail $cocktail; // (1)
:
public function setCocktail(Cocktail $cocktail) // (2)
{
$this->cocktail = $cocktail; // (3)
$this->cocktailName = $cocktail->name; // (3)
$this->cocktailPrice = $cocktail->price; // (3)
}
}
リスト8の(1)のように、Cocktailモデルクラスのプロパティと、(2)のようにそのセッタを定義します。セッタ内では(3)のようにプロパティに各値を格納します。
その上で、コンポーネントクラスでは、リスト9のように、mount()メソッド内でこのメソッドを呼び出してモデルオブジェクトを渡します。
class CocktailEdit extends Component
{
public CocktailForm $cocktailForm;
public function mount(Cocktail $cocktail)
{
$this->cocktailForm->setCocktail($cocktail);
}
:
}
なお、リスト9のmount()の引数は、Cocktailモデルオブジェクトとなっています。これは、コンポーネントクラスでも、Laravel本体同様に、ルートモデルバインディングが利用できるからです。
あとは、追加画面同様に、編集画面でもwire:modelを利用してcocktailFormの各プロパティを表示させれば、データベース内の値が入力コントロール上に表示されます。
まとめ
Laravelのフロントエンド的画面作成方法を紹介する連載の第2回目は、いかがでしたでしょうか。
今回は、前回に続いてLivewireを掘り下げ、よりフロントエンド的な処理の実装方法を紹介しました。Livewireに関しての解説は今回で終了です。
次回は、InertiaとVueを組み合わせた画面の作成方法の基礎を紹介します。
