この記事では、Eloquentが用意しているメソッドであるfresh()とrefresh()の挙動の違いについてです。
この2つのメソッドはモデルインスタンスを再構築してくれるものです。
しかしこの2つのメソッドには明確に違いがあります。
その違いを紹介していきます。
この2つのメソッドの使い方と違いを理解しておくと無駄なコードを減らせたりできるので知っておくと便利だと思います。
そしてこの再構築がなぜ必要なのかも併せて理解しておくと実務で実際に必要に応じて使用できるようになるかと思います。
この記事を読むメリット
- なぜfresh()とrefresh()が必要か理解できる
- fresh()とrefresh()の挙動の違いを理解できる
fresh()とrefresh()の必要性
まずはfresh()とrefresh()の必要性を確認したいと思います。
例として、usersテーブルに1つレコードを準備します。
mysql> select * from users;
+----+--------------+------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
| id | name | email | email_verified_at | password | remember_token | created_at | updated_at |
+----+--------------+------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
| 1 | laravel test | laravel@test.com | NULL | $2y$10$6ln2KbvP8dCRzYh.fcdNzuiqbncFBSp/ksGNkM5.npXOCI20Bfl.G | NULL | 2024-07-01 23:03:47 | 2024-07-01 23:03:47 |
+----+--------------+------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
idが1、nameが「laravel test」というユーザーが存在しています。
public function noFreshRefresh()
{
$user1 = User::find(1);
$user2 = User::find(1);
$user1->name = 'New Name';
$user1->save();
return view('no-fresh-refresh')
->with('user1Name', $user1->name)
->with('user2Name', $user2->name);
}
続いて$user1、$user2に同じデータを取得したモデルインスタンスを格納し、$user1のnameだけ更新し保存します。
この時の$user1と$user2のnameを比較したいと思います。
bladeで以下のように「$user1->name」と「$user2->name」を表示させてみます。
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 bg-white border-b border-gray-200">
<p>
{{ '$user1Name → ' . $user1Name }}
</p>
<p>
{{ '$user2Name → ' . $user2Name }}
</p>
</div>
</div>
</div>
</div>
その結果が以下になります。
モデルインスタンスは更新されない
$user1のnameを変更し、保存した時点でデータベースも更新されます。
mysql> select * from users;
+----+----------+------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
| id | name | email | email_verified_at | password | remember_token | created_at | updated_at |
+----+----------+------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
| 1 | New Name | laravel@test.com | NULL | $2y$10$6ln2KbvP8dCRzYh.fcdNzuiqbncFBSp/ksGNkM5.npXOCI20Bfl.G | NULL | 2024-07-01 23:03:47 | 2024-07-03 21:35:50 |
+----+----------+------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+
この時モデルインスタンスである$user1のnameも「New Name」に更新されています。
しかし、$user2のnameは「laravel test」のまま更新されていません。
これは$user2のモデルインスタンスを作成した時のデータと最新のデータベースの状態が一致していないからです。
では、それを解決するためにはどうすれば良いか。
そんな時に出てくるのがfresh()とrefresh()になります。
エンジニアにおすすめ書籍
エンジニアになりたて、これから勉強を深めていきたいという方におすすめの書籍はこちら!
fresh()とrefresh()の挙動の違い
先ほどの例でfresh()とrefresh()の必要性に触れました。
モデルインスタンスの状態をデータベースの最新に合わせて更新させるためにこの2つのメソッドを使用します。
では、fresh()とrefresh()の使い方とどのように結果が変わるか見てみたいと思います。
fresh()の挙動を確認
Eloquentを使ってそのユーザーデータを取得します。
public function fresh()
{
$user1 = User::find(1);
$user2 = User::find(1);
$user1->name = 'New Name';
$user1->save();
$freshUser = $user2->fresh();
return view('fresh')
->with('user1Name', $user1->name)
->with('user2Name', $user2->name)
->with('freshUserName', $freshUser->name);
}
$user1のnameを更新して保存するまでは先ほどと同じです。
この後、「$user1->fresh()」したものを「$freshUser」として格納します。
この時「$user1」「$user2」「$freshUser」の違いは以下のようになります。
$user2のnameは変更前の「laravel test」のままです。
しかし、fresh()を行ったものを格納した$freshUserは「New Name」と最新の状態が取得できています。
このように、fresh()メソッドは現在のモデルインスタンスと同じIDを持つ新しいモデルインスタンスをデータベースから取得します。
この時、既存のモデルインスタンスには変更を反映しません。
データベースから最新の情報を取得したいが、既存のモデルインスタンスをそのままにしたい場合に有用です。
fresh()が便利に使えるケースがあまり思いつかないですが。(笑)
refresh()の挙動を確認
続いてrefresh()の挙動を確認してみます。
public function refresh()
{
$user1 = User::find(1);
$user2 = User::find(1);
$user1->name = 'New Name';
$user1->save();
$user2->refresh();
return view('refresh')
->with('user1', $user1)
->with('user2', $user2);
}
結果は以下のようになります。
「$user2->refresh()」を行っているところがポイントです。
先ほどのfresh()は既存のモデルインスタンスに影響を与えませんでしたが、refresh()は既存のモデルインスタンスも最新に更新します。
新しい変数を用意して格納する必要なくデータベースの最新の状態に更新してくれます。
fresh()とrefresh()の必要性を理解しよう
いかがだったでしょうか。
fresh()とrefresh()の使い所とそれぞれのメソッドの違いが理解できたかと思います。
違いを理解できていないと思っていた結果が出なくて悩むことになりますのでこの機会に整理できてよかったです。
使い方を理解して適切な場所で使えると良いと思います。