Attaching records to a Laravel hasManyThrough relation

Viewed 5317

A simple and straight one:

How can I attach or detach new records when using a Laravel hasManyThrough relation the Laravel way? Model retrieving is obvious, from the docs here.

EDIT: In other words, is there a Laravelish way of doing the following smarter (model names taken from docs)?

$user = $country->users()->first;
$post->user_id = $user->id;
$post->save();

Thanks in advance.

2 Answers

https://laravel.com/api/5.8/Illuminate/Database/Eloquent/Relations/HasManyThrough.html

Yes, but you have to specify all the params.

firstOrNew 
// (Doesn't persist to DB, you have to manually call the save method later on the created model)
updateOrCreate 
// (Persists to DB)
rawUpdate 
// (Persists to DB, not recommended)

push is supposed to work too, according to the docs.

On a 1:M relationship, there's the save method available out of the box. That's because the only field Laravel has to fill in is the foreign key.

For example, Let's say you've got a Parent and Child models. When you call

$parent->children()->save(new Child(...));

Laravel fills in the foreign key and persists the model

If we had a GrandParent model as well, and we tried to save a child through a HasManyThrough relationship:

$grandparent->grandchildren()

Laravel would not only have to fill in for the Parent foreign key, but maybe even create a new Parent model as well since we're not sure it exists. That's why there's not a save method implemented.

Therefore, you can make something like

$grandparent->grandchildren()->firstOrNew(['parent_id' => $parent_id])->save();
// Or
$grandparent->grandchildren()->updateOrCreate(['parent_id' => $parent_id]);

You need a valid key too or else you'll get a SQL constraint violation.

hasManyThrough() requires an existing intermediate relationship. In the docs example, User is the intermediate relationship. Directly attaching a Post to a Country is not possible because it doesn't know which User owns it. You need to first attach it to the User.

Related