Laravel hasManyThrough equivalent: belongsTo relationship through another model
Solution 1
public function target() {
$middle = $this->belongsTo('Middle', 'middle_id');
return $middle->getResults()->belongsTo('Target');
}
Update:
Starting from laravel 5.8 you can use the hasOneThrough
relationship:
public function target() {
return $this->hasOneThrough('Target', 'Middle');
}
Solution 2
If this is situation like message in a bottle, and bottle is owned by the user (user > bottle > message
)
The only way I know to get the relation object is:
// THIS IS IN App\Message
public function bottle()
{
return $this->belongsTo('App\Bottle');
}
public function user()
{
return $this->bottle->belongsTo('App\User');
}
Solution 3
You can use hasOneThrough
but you need to customize keys.
public function parent()
{
return $this->hasOneThrough(Parent::class, Middle::class, 'id', 'id', 'middle_id', 'parent_id');
}
Origin belongs to Middle, and Middle belongs to Parent. Middle need has parent_id
foreign key, and Origin has middle_id
foreign key.
Finally you can use:
Origin::find(1)->parent;
Related videos on Youtube
BenjaminRH
I am a professional web developer. I make web apps with node.js (Meteor, Express) and Laravel, and code in Go and Python. My editor is Vim.
Updated on June 03, 2022Comments
-
BenjaminRH almost 2 years
I've got a model, it belongs to another model, that model belongs to a third model, and I want an eloquent method to relate the first model to the third one.
There doesn't appear to be a belongsToThrough (or hasOneThrough) method, though. I've already tried chaining multiple
belongsTo
methods, but that hasn't worked (Call to undefined method Illuminate\Database\Query\Builder::belongsTo()
). Any ideas?Here is an example of the models:
// The first model // Schema: this model has a middle_id column in the database class Origin extends Eloquent { public function middle() { return $this->belongsTo('Middle'); } } // The second model // Schema: this model has a target_id column in the database, but NOT an origin_id column class Middle extends Eloquent { public function target() { return $this->belongsTo('Target'); } } // The third model class Target extends Eloquent { }
What I'd like to do is add something like the following method to the
Origin
model:// A relationship method on the first "origin" model public function target() { // First argument is the target model, second argument is the middle "through" model, third argument is the database column in middle model that it uses to find the target model, or soemthing return $this->hasOneThrough('Target', 'Middle', 'target_id'); }
So that I can use
$originInstance->target->title
, etc.-
Jarek Tkaczyk about 10 yearshave you tried
hasManyThrough
? -
Jarek Tkaczyk about 10 yearsHasOne and HasMany both extend abstract HasOneOrMany and they are pretty similar. I'm pretty sure it will work for you, however it may return a Collection instead of a single model, that could be the only downsie I can think of now.
-
Jarek Tkaczyk about 10 yearsOK, then that's not going to work. There is no method for through relations this way currently, only the other way around
A -> hasOneOrMany -> B -> hasOneOrMany C
. but you can still use dot nested relations like origin->middle->target->title (if it's hasOne everywhere)
-
-
BenjaminRH about 10 yearsThanks, I appreciate the answer! I probably haven't phrased my question clearly enough, but my problem is that I need to access the target directly as a relation to the origin. As it is setup currently, I could use
$origin->middle->target
to access the target, because each one belongs to the next. However, that won't work for me, as I need to skip the middle-man. I hope that clears my problem up a bit. -
Yuri Scarbaci about 7 yearsI would like to know more about "getResults()", i am reading this answear 2 years later than it was posted in, and by a simple google search it looks like getResults() got replaced by get(). Still need to confirm this, but i hope it could help others looking at this in 2017!
-
Razor about 7 yearsAFAIK this answer is still valid, I double checked each
Relation
class andgetResults()
wasn't removed (e.g. HasMany Relation L5.4), did you test the answer? -
Jasmeet Singh over 6 yearsIt works. But is it efficient? Will this create a separate query for each bottle of each message, instead of running just one query for the entire request of a user.
-
Mladen Janjetovic over 6 years@JasmeetSingh, Of course it will create separate queries, but it makes life easier while coding. Having in mind that object caching is standard thing in apps these days, I don't mind. If you don't use such things you will just have to dance between ease of coding and app speed. One query for the entire request of a user with joins will be much faster, but it is not much reusable further in app. And we want to separate database layer from app so no raw SQL queries in code, neither
-
Mladen Janjetovic over 6 years@JasmeetSingh or you can just use Eager Loading
-
Charles Wood over 3 yearsUnfortunately this doesn't support eager loading :(
-
Charles Wood over 3 yearsOh man! I know that "thanks" comments are discouraged, but thank you so much! I couldn't believe this worked after all the other convoluted things I tried!
-
Razor over 3 years@CharlesWood Laravel added a function
hasOneThrough
that supports eager loading, I've updated my old answer, thanks. -
Marek Gralikowski over 3 yearsHappy to help ;)
-
Charles Wood over 3 years@Razor Nice! Bear in mind that to simulate
belongsToThrough
, you may need to customize the keys. See stackoverflow.com/a/58295018/1110820. (This is the solution I ended up using.)