laravel / ideas

Issues board used for Laravel internals discussions.
939 stars 28 forks source link

Add new relation DynamicBelongsTo Inspired By Jonathan Reinink #2520

Open ajcastro opened 3 years ago

ajcastro commented 3 years ago

I love the article Dynamic relationships in Laravel using subqueries by JonathanReinink.

In his final User class, the code is like this:

class User extends Model
{
    public function lastLogin()
    {
        return $this->belongsTo(Login::class);
    }

    public function scopeWithLastLogin($query)
    {
        $query->addSelect(['last_login_id' => Login::select('id')
            ->whereColumn('user_id', 'users.id')
            ->latest()
            ->take(1)
        ])->with('lastLogin');
    }
}

I propose to simplify this code into something like this by creating a new relation DynamicBelongsTo

class User extends Model
{
    public function lastLogin()
    {
        return $this->dynamicBelongsTo(Login::class, 'last_login_id', 'id')->query(function($query) {
            $query->select(
        });
    }
}

This new relation should be smart enough to perform the query $query->addSelect(['last_login_id' => Login::select('id')->whereColumn('user_id', 'users.id')->... to handle eagerloading and lazyloading naturally. Tho I'm not sure if this is possible but I think maybe it can.

reinink commented 3 years ago

I've considered this myself. However, my concern is that this pattern can be used in a lot of different ways...with a wide range of different possible subqueries. It becomes hard to create the right abstraction.

Further, while I LOVE this technique, and use it all the time, it's important to realize this is a hack, and therefore has some negative side affects. For instance, trying to update a model that's been loaded with a dynamic column will break, since the last_login_id doesn't exist. This is a perfectly fine tradeoff for when you're using this technique as a performance optimization in your app (you just make sure you don't do an update on those models), but if it existed as a real relationship type, I think that would be confusing.

Glad you found value in my blog post though! 🙌