laravel: laravelcollective/html から spatie/laravel-html に引っ越す

{!! !!} を使わせるパッケージの消滅

laravelcollective

laravel のコアパッケージが提供していた機能が何らかの理由により廃止された際、
当該廃止機能を移植して提供しようという、代替策を考えるのがめんどい人のための駆け込み寺みたいなパッケージでした。
簡単に言えば「多忙のためにプロジェクトの存続は無理だわ」という声明が出され、
気が付いたら abandoned flag が設定されていました。

laravelcollective/html はその中でも、blade 上で特に form 関連タグを対象とした
html タグのビルダを提供するものです。

主にどのような違いがあるのか

spatie/laravel-html はメソッドチェーン

laravelcollective/html では class や id 等を指定した連想配列を渡して構築していました。

{!! Form::select(
     'company_id',
     $companies,
     null,
     [
         'id' => null,
         'class' => ($errors->has('company_id')) ? 'form-control is-invalid' : 'form-control',
         'placeholder' => '選択してください',
         $canEdit ? null : 'disabled' => true,
     ]
) !!}

対して、spatie/laravel-html ではメソッドチェーンで明示的に何を追加するのかを指定して構築します。

{{ html()
     ->select('company_id', $companies)
     ->class('form-control')
     ->classIf($errors->has('company_id'), 'is-invalid')
     ->placeholder('選択してください')
     ->disabled(! $canEdit) }}

これにより、少なくとも class や id 等に関してタイポがあればすぐに例外が投げられるようになりました。

(disabled を条件句付きで指定するための構文が本当にクソキモかったのでそれが解消されたのが嬉しい)

条件句を指定して属性を付与するかどうかを選択できる

laravelcollective で無理やり条件句を埋め込んでいた箇所が一気に見やすくなります。

// laravelcollective
['class' => ($errors->has('company_id')) ? 'form-control is-invalid' : 'form-control',]

// spatie
->class('form-control')
->classIf($errors->has('company_id'), 'is-invalid')

条件句の結果に関わらず常に設定したい値(上記の例で言えば class の
form-control)を分離することができ、
複数の条件句で細かに制御したい場合に大いに役に立ちます。

属性に関しては以下のドキュメントのすべてのメソッドの接尾辞に If を付ければ、
第一引数で条件句を受け付けるメソッドになりますのでお好きなものを選びましょう。
Element methods | laravel-html | Spatie

分からないことがあれば公式ドキュメントで 7 割は解決する

残りの 3 割は vendor 配下のソースを直接読めば解決すると思います。

どんな html タグがあるのか、そのシグネチャは何か
HTML builder | laravel-html | Spatie

各タグにはどのようなメソッドが生えているのか
Element classes | laravel-html | Spatie
Element methods | laravel-html | Spatie

公式ドキュメントだけでは分かりにくいこと

select のグルーピング

laravelcollective/html では select() へネストにしたコレクション([string => Collection])を渡せば勝手に optgroup を作ってくれましたが、
spatie はコレクションが渡されても optgroup にしてくれません。

結論から言えば、コレクションを配列に変換したものを第二引数に渡しましょう。

{{ html()
     ->select('area_manager_id', $areaManagers->toArray()) }}
コレクションではダメな理由

第二引数に渡した配列の値が is_array() を条件として optgroup
を作るかどうかを判定しているからです。

public function options($options)
{
     return $this->addChildren($options, function ($text, $value) {
         if (is_array($text)) {
             return $this->optgroup($value, $text);
         }

モーダルを開くボタンは明示的に type="button" を指定しないとクリック時に遷移してしまう

html()->button('削除', 'button')

input が初期値とする値の優先順位

結論を言えば以下になります。
高| value() > old() > text(): 各 input の 第二引数 or 第三引数 > model の
attribute |低

バリデーションエラーがあってもフラッシュデータではなく表示したいものがあるなら value() で指定しましょう。

メソッドが GET の時(非バリデーションエラーの時)、クエリパラメータが初期値に反映されない

勝手にクエリパラメータを拾ってきた laravelcollective の設計があまり好きではなかった、というのが個人的な感想です。
spatie ではクエリパラメータを一切拾わないため、明示的に指定する必要があります。

{{ html()
     ->text('title')
     ->class('form-control')
     ->value(request()->query('title')) }}

request() の引数に直接指定しても拾えるんですが、挙動がキモいんで query() の方で指定してます。

上記の例では value() で指定していますが、text() で指定しても問題ないはずです。
特にバリデーションエラーが発生し得る場面ならば、text() にしないとフラッシュデータが反映されません。

form に対して 'enctype' => 'multipart/form-data' を設定したい

シンプルに acceptsFiles() をコールするだけで大丈夫です。

form()->acceptsFiles()

内部的には attribute() で付与してるだけのラップ関数になります。

File に disabled() が生えてない

どのような思想で生えてないのかは分かりませんが、
input type="file" を disabled にしたい場合は強引に attribute() で付与します。

attribute('disabled', '')