DBにデータを保存するときにお世話になるsaveメソッドでプチハマりした時の小ネタ
また同じことでハマらないように。
前置き
環境はLaravel5.7
何をしようとしたか
DB上のitemsテーブルにある決まった条件下のデータに対し、1つのカラムの値をupdateしたかったのでこんなコードを書きました。
カラム数の多いテーブルだったので、select時に取得するカラムを処理の中で使用するもののみに限定していました。
// 更新するデータを取得
$updateItemId = 'xxxxxx';
$item = Item::select('item_id')->where('item_id', $updateItemId)->first();
// 更新
$item->status = true;
$item->save();
しかし更新されない…トランザクションはってるけどコケてない…
何故?
そしてこれなら正しく更新される
// 更新するデータを取得
$updateItemId = 'xxxxxx';
$item = Item::where('item_id', $updateItemId)->first();
// 更新
$item->status = true;
$item->save();
ライブラリを見てみよう
フレームワークの機能で詰まったらググるかライブラリを掘る。
saveメソッドの処理はライブラリの
laravel/framework/src/Illuminate/Database/Eloquent/Model.php
こいつの中で行なっている模様。
saveメソッドを見つけて中を読んでみると、同じModel.phpのperformUpdateメソッドを呼び出している。
dd関数を駆使してどこで引っかかっているか検証していくと、updateメソッドを呼び出すところまでは順調だった。
で、肝心のupdateがここ!
$this->setKeysForSaveQuery($query)->update($dirty);
このsetKeysForSaveQueryが何をしているかというと、クエリのwhere句を作っている。
protected function setKeysForSaveQuery(Builder $query)
{
$query->where($this->getKeyName(), '=', $this->getKeyForSaveQuery());
return $query;
}
Model.phpの中で、getKeyNameメソッドではPKであるid
を、getKeyForSaveQueryはupdate対象の行のidの値を返している。
idの値がなければnullが返されているので、ここで生成されているwhere句は
where `id` = null
となる。id
= nullの条件に合致するデータはないので、updateすることなく処理が終わっていた。。
where句の条件がid
で固定されているので更新するデータを取得する時点でid
カラムも取得しないとだめか…
解決方法
結局こうしました
安直ですが他に方法が思いつかず。
// 更新するユーザーを取得
$updateItemId = 'xxxxxx';
$item = Item::select('id', 'item_id')->where('item_id', $updateItemId)->first();
// 更新
$item->status = true;
$item->save();
無事更新。
コード書くのもいいけどライブラリの処理追っていくのも楽しいです