1

The loop below works:

foreach($this->friends as $friend)
{
    foreach($friend->mailings as $mailing)
    {
        foreach($mailing->orders as $order)
        {
            $num_orders++;
        }

    }
}

But would like to do

foreach($this->friends->mailings->orders as $order)
{
    $num_orders++;
}

but when I do I get this error Property [mailings] does not exist on this collection instance.

The relationship between models is setup correctly (has many...etc)

Chris Muench
  • 17,444
  • 70
  • 209
  • 362
  • Have you thought about Eager Loading in the data during your SQL query? That would then allow you to already have all the data from your relationships. – jkruskie Apr 22 '19 at 17:20
  • It's not possible to do it that way. `friends` is a collection of friends, each friend has mailings, the entire collection doesn't have mailings and doesn't know what mailings is. – Devon Bessemer Apr 22 '19 at 17:27
  • Laravel has support for nested relationship as well as you're able to define default results for if the relationship has no results – jkruskie Apr 22 '19 at 17:44

1 Answers1

2

Edit: I found it! Jarek is a great writer for Eloquent, and I wanted to see if he had a trick for this. As always he does. :)

$this->load(['friends.mailings.orders' => function($q) use(&$orders){
    $orders = $q->get();
}]);

Now if you dd($orders) you will have a list of all orders from mailings from friends related to $this So you can now foreach over that to get what you want.

foreach($orders as $order){
    $num_orders++
}

His site has a certificate warning but this is where I got the above. https://softonsofa.com/laravel-querying-any-level-far-relations-with-simple-trick/

Please ignore the below, as it is no longer needed but I'm keeping it here for clarity and because it was accepted as the answer.

You can use the each() collection method to clean up your loops. Since there are many-to-many relationships you can't access the related models relations unless you iterate over them or specify which related item you want. See below:

$this->friends->each(function($friend, $key){
    $friend->each(function($mailing, $key2){
        $mailing->orders->each(function($orders, $key3){
            $num_orders++;
        })  
    });
})

https://laravel.com/docs/5.8/collections#method-each

There's also the withCount() query builder method that you may want to look into. It doesn't seem to like nested relations using the regular dot notation, but I haven't used it enough to say whether or not it can be used here. I stumbled upon Laravel 5.3 withCount() nested relation while looking into the withCount() part. Seems like it may be possible but you will have to change your relations to hasManyThrough(). It should be a good place to start.

N Mahurin
  • 1,406
  • 10
  • 18
  • Important to note how expensive this operation is on a large collection, since this is an n*2 operation. If you have a collection of 100 items, you're performing 201 queries to get this data. (One for the original get, one for each load, one for each get inside the closure). – Devon Bessemer Apr 22 '19 at 19:21