staudenmeir / belongs-to-through

Laravel Eloquent BelongsToThrough relationships
MIT License
1.15k stars 88 forks source link

whereBelongsTo not working #94

Closed levu42 closed 8 months ago

levu42 commented 8 months ago

Laravel's whereBelongsTo isn't working, because QueriesRelationships.php checks if the relationship is an instance of BelongsTo.

Is it realistic to change the BelongsToThrough class to be a subclass of BelongsTo instead of Relation?

staudenmeir commented 8 months ago

Hi @levu42, This is a more fundamental issue: whereBelongsTo() can't work with BelongsToThrough relationships because the necessary ID is not an attribute of the model.

Consider the example from the README:

class Post extends Model
{
    use \Znck\Eloquent\Traits\BelongsToThrough;

    public function country()
    {
        return $this->belongsToThrough(Country::class, User::class);
    }
}

You can't query Post::whereBelongsTo($country) because you need the user's ID since the foreign key is posts.user_id.

levu42 commented 8 months ago

@staudenmeir yes, I totally get that! It would need to do something like where user_id IN(select id from users where country_id = ?) using subqueries. Currently, I build these subqueries manually, is there some way to do something similar to whereBelongsTo with current code?

It would of course be magic, if I could just put a BelongsToThrough into whereBelongsTo method at some point, not having to worry about the implementation details, when I write my query logic. Maybe that could be achieved by extracting the necessary parts from BelongsTo into a contract that can be implemented both by BelongsTo & BelongsToThrough, so that whereBelongsTo can work with both.

staudenmeir commented 8 months ago

You're looking for whereHas(). The short version for your use case is whereRelation():

$posts = Post::whereRelation('country', 'countries.id', $country->id)->get();

The better and faster way would be to (define and) use the inverse relationship:

$posts = $country->posts;
levu42 commented 8 months ago

@staudenmeir oh, thanks! I totally forgot about whereRelation() because I got so used to using whereBelongsTo. The case I use it for needs it this way round, so the inverse relationship I can't use in that case. Thanks for your help :)