maximos's avatar

Eager loading for belongsToMany pivot table

I have this structure:

class Place extends Model
{
    public function discounts(): BelongsToMany
    {
        return $this->belongsToMany(Discount::class)->using(DiscountPlace::class)->withPivot('id');
    }
}

class Discount extends Model
{
    public function places(): BelongsToMany
    {
        return $this->belongsToMany(Place::class)->using(DiscountPlace::class)->withPivot('id');
    }
}

class DiscountPlace extends Pivot
{
    public $incrementing = true;

    public function activities(): MorphMany
    {
        return $this->morphMany(Activity::class);
    }
}

Now I have to load activities for each discount in a loop:

$place = Place::with('discounts')->first();

$place->discounts->map(fn($discount) => $discount->pivot->load('activities'));

As a result, I receive a lot of queries:

select * from `activity_log` where `activity_log`.`subject_type` = 'App\\Models\\DiscountPlace' and `activity_log`.`subject_id` = 1 and `activity_log`.`subject_id` is not null
select * from `activity_log` where `activity_log`.`subject_type` = 'App\\Models\\DiscountPlace' and `activity_log`.`subject_id` = 2 and `activity_log`.`subject_id` is not null
select * from `activity_log` where `activity_log`.`subject_type` = 'App\\Models\\DiscountPlace' and `activity_log`.`subject_id` = 3 and `activity_log`.`subject_id` is not null
/** etc... */

How can my task be done better without third-party libraries?

0 likes
4 replies
krisi_gjika's avatar

why not make DiscountPlace a model? pivots are meant for simple tables linking 2 models, but if they grow to be more complex you are better of an extra model.

maximos's avatar

What do you mean? class DiscountPlace extends Model {}?

krisi_gjika's avatar

yes, so you can have relations such as

Place::with('discounts.discountPlaces.activities')->get()

Please or to participate in this conversation.