この記事で扱う Laravel のバージョンは 8.75.0 です。実際に動作確認していませんが GitHub を見るに 5.2.0 以降で共通な動作です。
Laravel にはシーダーというデータベースに値を入れるためのコードの置き場があります。これはphp artisan db:seed
で実行されテストデータ、初期データを作ります。
データベース:シーディング 8.x Laravel
このシーダーですが次の様な fill メソッドを用いたコードを書くとエラーを起こします。
-- テーブル定義(PostgreSQL) create table table_name ( id serial constraint table_name_pk primary key, name varchar(255) );
/** モデル */ class TestTable extends Model { protected $table = 'table_name'; protected $fillable = [ 'name', ]; }
/** シーダー */ (new TestTable)->fill([ 'name' => '浜松太郎', 'name_kana' => 'はままつたろう', ])->save(); /* エラー内容 SQLSTATE[42703]: Undefined column: 7 ERROR: column "name_kana" of relation "table_name" does not exist LINE 1: insert into "table_name" ("name", "name_kana", "updated_at",... ^ (SQL: insert into "table_name" ("name", "name_kana", "updated_at", "created_at") values (浜松太郎, はままつたろう, 2021-12-20 10:32:43, 2021-12-20 10:32:43) returning "id") */
存在しないカラムである name_kana を INSERT しようとしてエラーが発生します。fill メソッドと fillable プロパティが本来の通りに動作するならば fill を実行した時点で name_kana は落とされ、問題なく INSERT が成功します。
Eloquentの準備 8.x Laravel#複数代入
しかし、実際にはエラーが起こります。fill メソッドが動作していません。
この挙動は次の db:seed で実行されるコマンドクラス中にある次のコードが原因です。
framework/SeedCommand.php at 8.x · laravel/framework#SeedCommand.php#L65
public function handle() { // 略 Model::unguarded(function () { $this->getSeeder()->__invoke(); });
Model::unguarded は渡したコールバックの処理中 Eloquent の基底クラスの unguarded プロパティを true にするメソッドです。unguarded プロパティを true にして何が起こるかというと fillable, guarded プロパティによる複数代入のガード機能である代入するキーの絞り込みが動作しなくなります。これによりシーダークラス実行中は fill による絞り込みが効かず、未定義カラムを INSERT しようとしてエラーが発生しました。
これを対策するならば次の様になります。
\Illuminate\Database\Eloquent\Model::reguard(); (new TestTable)->fill([ 'name' => '浜松太郎', 'name_kana' => 'はままつたろう', ])->save();
reguard メソッドで unguarded を false にしてfill を有効化します。