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()はいったいどういうときに使用するのでしょうかね。

By khino