tinkerを使用して開発中の関数をいろいろ試験します。Eloquent関連の関数で複数のDBテーブルに渡り値を更新する関数ゆえに、tinkerがとても役に立つのです。しかし、試験中に不思議なことが起こりました。ちょっと格闘して、なるほどそこではこうすればいいのだな、という話を共有です。
まず、説明のためにhasManyのフェイクデータの作成のポストで環境を作成します。
以前のレコードが残っているかもしれないので、truncate()
を実行して空にします。そこでfactory()
を実行して、Userのレコードを1つ、Addressのレコードを2つ作成します。$user->addresses
は、Userのモデルのrelationshipです。
$ php artisan tinker sy Shell v0.9.9 (PHP 7.2.16 — cli) by Justin Hileman >>> use App\User; >>> use App\Address; >>> User::truncate(); >>> Address::truncate(); => Illuminate\Database\Eloquent\Builder {#2974} >>> factory(App\User::class)->create()->each(function ($user) { $user->addresses()->saveMany(factory(App\Address::class, 2)->make()); }); => true >>> $user = User::find(1); => App\User {#2976 id: 1, name: "三宅 桃子", email: "kaori01@example.org", email_verified_at: "2019-08-29 20:45:31", created_at: "2019-08-13 07:57:01", updated_at: "2019-08-13 07:57:01", } >>> $user->addresses; => Illuminate\Database\Eloquent\Collection {#2986 all: [ App\Address {#2982 id: 1, user_id: 1, address: "8427481 東京都松本市西区山田町廣川6-3-5 ハイツ喜嶋108号", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 20:45:31", }, App\Address {#2974 id: 2, user_id: 1, address: "9979251 茨城県加藤市北区原田町山口7-7-5", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 20:45:31", }, ], }
さて、ここで$userの名前を変更してみます。
>>> $user->name = 'TEST'; => "TEST" >>> $user => App\User {#2976 id: 1, name: "TEST", email: "kaori01@example.org", email_verified_at: "2019-08-29 20:45:31", created_at: "2019-08-13 07:57:01", updated_at: "2019-08-13 07:57:01", addresses: Illuminate\Database\Eloquent\Collection {#2986 all: [ App\Address {#2982 id: 1, user_id: 1, address: "8427481 東京都松本市西区山田町廣川6-3-5 ハイツ喜嶋108号", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 20:45:31", }, App\Address {#2974 id: 2, user_id: 1, address: "9979251 茨城県加藤市北区原田町山口7-7-5", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 20:45:31", }, ], }, }
変わりましたね。しかし、まだ$user->save()
を実行していないので、単に$userのインスタンスの値が変わっただけです。これをリセットするには、fresh()
を使用します。
>>> $user->fresh(); => App\User {#2979 id: 1, name: "三宅 桃子", email: "kaori01@example.org", email_verified_at: "2019-08-29 20:45:31", created_at: "2019-08-13 07:57:01", updated_at: "2019-08-13 07:57:01", } >>>
戻りましたね。しかし、$user自体は戻っていません。
>>> $user => App\User {#2976 id: 1, name: "TEST", email: "kaori01@example.org", email_verified_at: "2019-08-29 20:45:31", created_at: "2019-08-13 07:57:01", updated_at: "2019-08-13 07:57:01", addresses: Illuminate\Database\Eloquent\Collection {#2986 all: [ App\Address {#2982 id: 1, user_id: 1, address: "8427481 東京都松本市西区山田町廣川6-3-5 ハイツ喜嶋108号", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 20:45:31", }, App\Address {#2974 id: 2, user_id: 1, address: "9979251 茨城県加藤市北区原田町山口7-7-5", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 20:45:31", }, ], }, }
不思議ですね。
APIのマニュアルを見てみましょう。
https://laravel.com/api/5.8/Illuminate/Database/Eloquent/Model.html#method_fresh
そこの説明では、
Reload a fresh model instance from the database.
DBから新しいインスタンスをリロード、とありますが、元のインスタンスをリセットするのではなく、新しいインスタンスを作成して返しているようです。
つまり、元のインスタンスのリセットには、
>>> $user = $user->fresh(); => App\User {#2979 id: 1, name: "三宅 桃子", email: "kaori01@example.org", email_verified_at: "2019-08-29 20:45:31", created_at: "2019-08-13 07:57:01", updated_at: "2019-08-13 07:57:01", } >>> $user => App\User {#2979 id: 1, name: "三宅 桃子", email: "kaori01@example.org", email_verified_at: "2019-08-29 20:45:31", created_at: "2019-08-13 07:57:01", updated_at: "2019-08-13 07:57:01", }
と元のインスタンスに割り当てが必要となります。面倒ですね。fresh()
は違う使用ケースがあるのでしょうか。
と思っていたら、そのためにもう1つのメソッドrefersh()
がありました。
>>> $user->name = 'TEST'; => "TEST" >>> $user; => App\User {#2979 id: 1, name: "TEST", email: "kaori01@example.org", email_verified_at: "2019-08-29 20:45:31", created_at: "2019-08-13 07:57:01", updated_at: "2019-08-13 07:57:01", } >>> $user->refresh(); => App\User {#2979 id: 1, name: "三宅 桃子", email: "kaori01@example.org", email_verified_at: "2019-08-29 20:45:31", created_at: "2019-08-13 07:57:01", updated_at: "2019-08-13 07:57:01", } >>> $user => App\User {#2979 id: 1, name: "三宅 桃子", email: "kaori01@example.org", email_verified_at: "2019-08-29 20:45:31", created_at: "2019-08-13 07:57:01", updated_at: "2019-08-13 07:57:01", } >>>
一件落着です。このrefresh()
のメソッド、関連しているレコードの反映にも役立つことわかりました。
例えば、
>>> $user->addresses; => Illuminate\Database\Eloquent\Collection {#2986 all: [ App\Address {#2982 id: 1, user_id: 1, address: "8427481 東京都松本市西区山田町廣川6-3-5 ハイツ喜嶋108号", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 20:45:31", }, App\Address {#2974 id: 2, user_id: 1, address: "9979251 茨城県加藤市北区原田町山口7-7-5", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 20:45:31", }, ], }
のように、ユーザーには2つの住所があります。ここの1つを更新してみます。
>>> $address = Address::find(1); => App\Address {#3015 id: 1, user_id: 1, address: "8427481 東京都松本市西区山田町廣川6-3-5 ハイツ喜嶋108号", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 21:16:30", } >>> $address->update(['address' => 'TEST ADDRESS']); => true
しかし、以下を実行すると、
>>> $user->addresses => Illuminate\Database\Eloquent\Collection {#2971 all: [ App\Address {#2970 id: 1, user_id: 1, address: "8427481 東京都松本市西区山田町廣川6-3-5 ハイツ喜嶋108号", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 20:45:31", }, App\Address {#2981 id: 2, user_id: 1, address: "9979251 茨城県加藤市北区原田町山口7-7-5", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 20:45:31", }, ], }
最初のアドレスのレコードは、オリジナルのままですね。
そこで、refersh()
を使いましょう。
>>> $user->refresh(); => App\User {#2979 id: 1, name: "三宅 桃子", email: "kaori01@example.org", email_verified_at: "2019-08-29 20:45:31", created_at: "2019-08-13 07:57:01", updated_at: "2019-08-13 07:57:01", addresses: Illuminate\Database\Eloquent\Collection {#3022 all: [ App\Address {#3020 id: 1, user_id: 1, address: "TEST ADDRESS", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 21:17:12", }, App\Address {#3023 id: 2, user_id: 1, address: "9979251 茨城県加藤市北区原田町山口7-7-5", created_at: "2019-08-29 20:45:31", updated_at: "2019-08-29 20:45:31", }, ], }, }
変更が反映されましたね。しかし、fresh()
はいったいどういうときに使用するのでしょうかね。