2
votes

I am trying to eliminate unnecessary queries on my site but am struggling to wrap my head around Eager Loading and Lazy Loading. All users on my site have listings, and listings have multiple users. They are connected through the table listing_users. Every listing then has one "order" associated with it. Here is the user model:

User Model:

public function listings(){
   return $this->belongsToMany(Listing::class)->withPivot('role_id');
}

Listing Model:

  public function order(){
   return $this->hasOne(Order::class)->first();
  }

My current dashboard is loaded by calling this viewListings in the UserController:

public function viewListings(){
  $user = Auth::user();
  $listings = $user->listings()->orderBy('created_at','desc')->get();
  return view('user.listings', compact('listings'));
}

The problem occurs in my blade view user.listings where I have a foreach loop for every listing and then call each order as well. I need a way to pass the listings to the page, with their related orders.

  @foreach($listings as $listing)
    @if($listing->order()->status == 'completed')
      {{-- Display the listing details here --}}
    @endif
  @endforeach 

Any advice into the above situation would be greatly appreciated! I'm sure there is a simple Laravel solution for this that I'm overlooking.

1

1 Answers

0
votes

Try this:

Listing Model:

public function order(){
  return $this->hasOne(Order::class); //without first()
}

UserController: Here we use method with('order') for eager loading Order model for each Listing models retrieved by query. So now in your blade will not be unnecessary queries.

When accessing Eloquent relationships as properties, the relationship data is "lazy loaded". This means the relationship data is not actually loaded until you first access the property. However, Eloquent can "eager load" relationships at the time you query the parent model.

public function viewListings(){
  $user = Auth::user();
  $listings = $user->listings()->orderBy('created_at','desc')
  ->with('order')->get();//added with('order')
  return view('user.listings', compact('listings'));
}

user.listings: You should use order without () if you need retrieve your model. So if you want modify order then use it with () as query builder, and add further constraints like where, orderBy etc. and in the end add first(). Here you can understand why we removed first() from hasOne above.

@foreach($listings as $listing)
   @if($listing->order->status == 'completed')
    {{-- order instead of order() --}} 
     {{-- Display the listing details here --}}
   @endif
@endforeach