終電23時15分って早くね?

都内のIT企業で働くカラオケ大好きエンジニアの雑記

Laravel4のEloquent ORMではまった件

掲題の件、めちゃめちゃはまりました。。

格闘すること数時間。
結果解決したのでホッとしているんですが、
備忘録と同じようなエラーではまっている人のために、
(そもそもはまる人がいるのかわかんないけど 笑)
ログとして残しておこうと思います。

やろうとしたこと


Eloquent ORMはLaravel4にデフォルトで含まれている。
コレを使うとModelとデータベース(のテーブル)を関連付けて、
簡単にデータ操作ができるようになります。

今回、ユーザーを管理するモデルとデータベースのテーブルとして以下をはじめに用意しました。

【Userモデル】

class User extends Eloquent {

     /**
     * モデルに関連付けるデータベースのテーブルを指定
     *
     * @var string
     */
     protected $table = 'users';

}

【usersテーブル】

mysql> desc users;
+------------+------------------+------+-----+---------------------+----------------+
| Field      | Type             | Null | Key | Default             | Extra          |
+------------+------------------+------+-----+---------------------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL                | auto_increment |
| email      | varchar(255)     | NO   | UNI | NULL                |                |
| login_name | varchar(255)     | NO   |     | NULL                |                |
| created_at | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
| updated_at | timestamp        | NO   |     | 0000-00-00 00:00:00 |                |
+------------+------------------+------+-----+---------------------+----------------+

※本当はパスワードとかその他もろもろ情報を付け足す予定でしたが、
まず最初の段階でがっつりつまづいたので、最低限のテーブル構造になってます。

■Laravel4 日本語ドキュメント - Eloquent ORM
http://laravel4.kore1server.com/docs/eloquent

この日本語ドキュメントの、
基本的な使用法

にもありますが、

一度モデルを定義したら、テーブルのレコードを取得したり、作成したりする準備は整います。

と書いてある!
「よっしゃー超簡単じゃーん♪」
と思ってしまったのがコトの発端です。。


早速新しいデータを追加してみよう!

と思った私は、

routes.php

Route::get('test', function()
{
    $user = User::create(array('email' => 'test@test.com','login_name' => 'test',));   
});

を追加して、/test にアクセスし、
新規データを追加しようと試みました。

が、
Illuminate \ Database \ Eloquent \ MassAssignmentException
ばっちりエラー画面が表示。。

なぜ・・
挿入するデータを替えてみたり、
データベースの文字コードを確認してみたり、
Eloquentクラスの中身を追ってデバッグしてみたり・・・
と色々試してみたんですが、どうにも解決せず。。


何がいけなかった?

■edongkoy | Tutorials: Laravel 4 MassAssignmentException Error
http://tutorials-edongkoy.blogspot.jp/2013/06/laravel-4-massassignmentexception-error.html

ようやく解決させてくれたのが上の記事でした。

Eloquent ORMを利用して、モデルとデータベースのテーブルを関連付け、
createメソッドでデータを挿入するためには、

protected $guarded = array('hogehoge');

もしくは

protected $fillable = array('hogahoga');

の設定が必ず必要!ということです。

要するに、今回のケースでいくと、

class User extends Eloquent {

     /**
     * モデルに関連付けるデータベースのテーブルを指定
     *
     * @var string
     */
     protected $table = 'users';

     /**
     * createメソッド実行時に、入力を禁止するカラムの指定
     *
     * @var array
     */
     protected $guarded = array('id');

}

または

class User extends Eloquent {

     /**
     * モデルに関連付けるデータベースのテーブルを指定
     *
     * @var string
     */
     protected $table = 'users';

     /**
     * createメソッド実行時に、入力を許可するカラムの指定
     *
     * @var array
     */
     protected $fillable = array('email','login_name');

}

と書く必要がありました。

てか、これぶっちゃけドキュメントに書いてあるんです。。笑
(ちゃんと読め!ってはなし)

もしくは一行で新しいモデルを保存するためにcreateメソッドを使用することも可能です。メソッドから挿入されたモデルのインスタンスがリターンされます。しかしながら全Eloquentモデルは複数代入から保護されているため、これを使用する前に操作対象のモデルに対しfillableかguardedプロパティのどちらかを指定しておく必要があります。

http://laravel4.kore1server.com/docs/eloquent#insert-update-delete

操作対象のモデルに対し、
※ fillableかguardedプロパティのどちらかを指定しておく必要があります。 ※
(これ重要。)

ということで、今回は

class User extends Eloquent {

     /**
     * モデルに関連付けるデータベースのテーブルを指定
     *
     * @var string
     */
     protected $table = 'users';

     /**
     * createメソッド利用時に、入力を受け付けないカラムの指定
     *
     * @var array
     */
     protected $guarded = array('id'); // この行を追加。

}

とプログラムを修正することで、
ようやっと、迷宮から脱出することができましたとさ。。

今回の場合で上記のように設定したのは、
idのカラムはauto_incrementが設定されていて、
createメソッドでの入力に応じて値が変化する想定ではなかったので、
このような指定にしました。


でもさ・・・

一度モデルを定義したら、テーブルのレコードを取得したり、作成したりする準備は整います。

「作成する準備」は整ってないよね(>_<)