【Laravel5】Laravel Collective 5.2 Form Model Bindingの落とし穴
こんにちは、ナカエです。
Laravel5でLaravel4のようにHTMLとFormのファサードを利用したい場合は
laravelcollective/htmlを利用するのが一般的です。
Laravel CollectiveはHTMLとFormのほかにもLaravelコアから取り除かれたコンポーネントをメンテナンスしているプロジェクトです。
※以下の内容はLaravel 5.2、Laravel Collective 5.2.3で確認しています。
Form Model Binding
Formファサード(中で仕事しているのはFormBuilderクラスですが)で提供されている機能の一つであるForm Model Bindingを利用すると、 Modelのインスタンスをフォームに紐づけ、 Modelのプロパティ名を指定するだけで、Modelのインスタンスの対応する値が読み込まれるようになります。 これにより、単一のModelのフォーム作成をすっきりと書くことができます。
問題点
Form Model Bindingを利用する際、 Modelクラスのプロパティと同じ名前のカラム名を採用していると、
Modelの$attributesに入っている値ではなく、 Modelのプロパティの値がそのまま露出してしまいます。
特にプロパティがprotectedの場合でもその値が取り出されてしまうので、 我々が想像する動作とは違った挙動になることがあります。
例)'original'など
{!! Form::model($article, ['route' => ['articles.update', $article->id], 'method' => 'put']) !!}
origina: {!! Form::text('original') !!}
{!! Form::close() !!}
→この場合はoriginalプロパティの値が配列で取得されるので配列から文字列への変換エラーが起こります。
解決策 【注:Laravel Collective 5.2 が必要です】
FormBuilderのソースを読んでみると、2015/12/1付けでlaravelcollective/htmlにFormAccessibleというTraitが追加されていることがわかりました。
ModelにこのTraitを利用するとModelからの値の取り出しにFormAccesbileで定義しているメソッドが使われるようになり、
Modelのプロパティと名前が衝突している場合でも$attributesの中の値が取り出せます。
<?php
namespace App;
use Collective\Html\Eloquent\FormAccessible;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
use FormAccessible;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'original',
'hidden',
'table',
'timestamps',
'exists',
];
}