5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravelのphpunitでfactoryで作成したモデルにIDがなくて泣いた

Posted at

概要

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は未検証)

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?