3年前に書いた投稿の更新です(その投稿自体その4年前の投稿の更新です)。factoryからEloquentのインスタンスの作成も変わり、また新たな発見がありました。
まず、tinkerを使用して、isDirty()
の復習です。
factory()
を使って、1つレコードを作成します。
>>> User::factory()->create(); => App\Models\User {#3632 name: "村山 涼平", email: "ekoda.asuka@example.com", email_verified_at: "2022-06-12 20:18:11", #password: "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", #remember_token: "h7d19XhYd4", updated_at: "2022-06-12 20:18:11", created_at: "2022-06-12 20:18:11", id: 1, }
作成したレコードの名前を更新しますが、DBでなくオブジェクトのみの更新のために、fill()
を使用します。
>>> $user = User::find(1); => App\Models\User {#3949 id: 1, name: "村山 涼平", email: "ekoda.asuka@example.com", email_verified_at: "2022-06-12 20:18:11", #password: "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", #remember_token: "h7d19XhYd4", created_at: "2022-06-12 20:18:11", updated_at: "2022-06-12 20:18:11", } >>> $user->fill(['name' => '山田太郎']); => App\Models\User {#3949 id: 1, name: "山田太郎", email: "ekoda.asuka@example.com", email_verified_at: "2022-06-12 20:18:11", #password: "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", #remember_token: "h7d19XhYd4", created_at: "2022-06-12 20:18:11", updated_at: "2022-06-12 20:18:11", }
nameが変わりましたね。
実際、オブジェクトが更新したかどうかは、isDirty()
を使います。
>>> $user->isDirty(); => true
変更していますね。
項目ごとはどうでしょう?
>>> $user->isDirty('name'); => true >>> $user->isDirty('email'); => false
nameの変更がありますが、emailの変更はなしです。正しいです。
ここで、変更したオブジェクトをもとに対応するレコードをDBに保存します。
>>> $user->save(); => true
さて、この時点でのisDirty()
の返り値は?
>>> $user->isDirty(); => false >>> $user->isDirty('name'); => false
もう、isDirty()
では、変更があったかどうかの判断はできません、何もDirtyではありません。
この時点、つまりオブジェクトの更新をDBに反映した時点でレコードが更新したかどうかを判断するには、isDirty()
ではなく、wasChanged()
を使用します。
>>> $user->wasChanged(); => true >>> $user->wasChanged('name'); => true >>> $user->wasChanged('email'); => false
save()
前のisDirty()
の結果とまったく同じです。
実際には、こんなコードでwasChanged()
は使われます。
... $user->fill(['name' => '山田太郎']); if ($user->isDirty()) { $user->save(); if ($user->wasChagned('name')) { //nameが更新されたときのみ、以下のコードを実行 ... } } ...
さてさて、上の話は既存にあるレコードを更新したときの話です。新規のレコード作成のときもチェックしてみます。
>>> $user = User::factory()->make(); => App\Models\User {#4588 name: "浜田 京助", email: "tsubasa.saito@example.org", email_verified_at: "2022-06-12 20:21:59", #password: "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi", #remember_token: "ZzZh0fHqJA", }
先ほどと違うのは、create()
の代わりにmake()が使用されているところです。create()
と違ってまだDBレコードは作成されていません。
この時点では、
>>> $user->isDirty(); => true
更新と同じですね。
DBにレコードを保存してみます。
>>> $user->save(); => true
さて、この時点でのisDirty()
の返り値は?
>>> $user->isDirty(); => false
期待通りです。
しかし、
>>> $user->wasChanged(); => false
こちらは、更新時と違ってtrueとはなりません。wasChangedは訳せば更新したかという意味であり、作成されたかではないとすればfalseになるのは正しいのでしょう。
しかし、$userのようなインスタンスが既存のレコードを更新したのか、新規に作成されたのかが前もってわからないときの判断としてwasChanged()
を使用できません。とかいってwasCreated()
というメソッドもないのです。滅多に直面するケースは少ないですが、注意しましょう。