概要
phpunitでテストを書いているときに、factoryでモデルを作ってそのIDを利用するみたいなコードを書きました。
$user = factory(User::class)->create();
$id = $user->id;
しかしなぜかidがないよ!と怒られたり、idが0になっていたりしました。DBにはきちんと保存されているのに。
結論
モデルにはきちんとincrementing
プロパティを指定しましょう。
説明
id(PK)は基本的にオートインクリメントになるように設定していると思いますが、テーブルによってはオートインクリメントしていないものもあります。
オートインクリメントしないモデルには$incrementeng = false
を指定しましょう。(デフォルトではtrue
になっています。)
また、中間テーブルでオートインクリメントを指定している、かつPivot
を継承している場合はtrue
を指定しましょう。Pivot
はデフォルトではfalse
に設定されています。
余談
なんでidが0になったりするかというと、$incrementing
の値で処理を分けていて、
if ($this->getIncrementing()) {
$this->insertAndSetId($query, $attributes);
}
// If the table isn't incrementing we'll simply insert these attributes as they
// are. These attribute arrays must contain an "id" column previously placed
// there by the developer as the manually determined key for these models.
else {
if (empty($attributes)) {
return true;
}
$query->insert($attributes);
}
オートインクリメントのときはレコードをinsertした後に設定されたidを取得してくるという動作をしています。
insertAndSetId
のなかにinsertGetId
という処理があり、最終的にPDOのlastInsertId
というメソッドを呼んでidを取得しています。
lastInsertId
というメソッド名だけ見ると、オートインクリメントじゃなくてもidを取ってきてくれそうですが、このメソッドはDBの種類によって挙動が変わるっぽいです。
mysqlだとauto_incrementが設定されていないとだめみたいです。
なので、idをオートインクリメントにしていないのにモデルが$incrementing = true'の状態だと、
lastInsertId`が呼ばれますがidは0で返ってくることになります。(postgresは未検証)