はじめに
先日ある機能を実装していた時に、早とちりで「DBが更新されていない!」と慌てた時の話を書いていこうと思います。
実装
DBのHogehogeレコードのfugaフラグを変更するという処理を実装しようとしました。
App\Hogehogeのモデルの$fillableにfugaが設定されているという状況下で、まずHogehogeRepositoryクラスにフラグ変更用のメソッドを記述しました。
<?php
namespace App\Repositories;
use App\Hogehoge;
class HogehogeRepository
{
private $hogehoge;
public function __construct(Hogehoge $hogehoge)
{
$this->hogehoge = $hogehoge;
}
public function setFugaFlag(int $id)
{
return $this->hogehoge->find($id)->fill(['fuga' => 1])->save();
}
}
このメソッドの動作を確認する為、Tinkerで以下のような動作確認をしました。
$hogehoge = App\Hogehoge::first();
// => App\Hogehoge { #....
// ...
// }
$hogehoge->fuga = 0;
// => 0
$hogehoge->save()
// => true
$repo = app(App\Repositories\HogehogeRepository::class);
// => App\Repositories\HogehogeRepository {#....}
$repo->setFugaFlag($hogehoge->id);
// => true
$hogehoge;
// => App\Hogehoge { #....
// ...
// fuga: 0
// }
すると、値が変更されているはずのところ、変更前の値が出てきました。
なぜこうなったか
Tinkerの中で$hogehogeの値を設定した後、HogehogeRepositoryのメソッドで$hogehogeに対応するレコードを更新しています。しかし、その後意図的に$hogehogeを更新しなければ、$hogehogeに最新のレコードの値は反映されないようでした。
解決方法
変数$hogehogeは更新されていませんが、対応するDBのレコードは更新されているので、新たにレコードを取得することで確認することができます。
// $repo->setFugaFlag($hogehoge->id);
App\Hogehoge::find($hogehoge->id);
// => App\Hogehoge { #....
// ...
// fuga: 1
// }
また、変数$hogehoge自体を更新することもできます。
// $repo->setFugaFlag($hogehoge->id);
$hogehoge->refresh();
// => App\Hogehoge { #....
// ...
// fuga: 1
// }
補足
今回Tinkerでモデルオブジェクトが更新されなかったことについて書きましたが、テストコード等Tinker以外の場所のコードでも起こるようです。特にテストコード内では「実際にモデルorDBの値が変更されていることを確認する」という動作を書くことが多そうなので、注意が必要になりそうです。