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