How can I access data via relationship

Published 4 weeks ago by Melodia

I have a user that has many properties. This is user should also be able tp view the offers bet on his properties.

So have the relationship set.

User.php

public function properties(){
    return $this->hasMany('App\Property');
}

Property.php

public function offers(){
    return $this->hasMany('App\Offer');
}

Then in my controller this is what I have:

public function my_offers(){
    
    $properties = Property::whereUserId(Auth::id())->get();


    return view('pages.seller.offers.index', compact('properties'));
}

Then I go to my views like this:

@if($properties)
<ul>
    @foreach($properties as $property)

        <li>{{$property->offers->offer_message}}</li>

    @endforeach
</ul>
@endif 

When I view the page I see the below error:

Property [offer_message] does not exist on this collection instance.

But this property exists in my table.

If I change my list item to the one below I can see the array:

 <li>{{$property->offers-}}</li>

I also see that before and after the array with the data, there are two empty arrays.

Is there anything that I didnt correctly?

Hope someone can help

Cronix
Cronix
4 weeks ago (783,370 XP)

First, eager load the offers. Otherwise you will be executing extra queries in your loop (N+1 query problem)

$properties = Property::with('offers')->whereUserId(Auth::id())->get();

Next, offers() is a hasMany() relationship, which means it will return an array of results. So you need to iterate over it and access the items in that array as well.

@foreach($properties as $property)
    <ul>
    @foreach ($property->offers as $offer)
        <li>{{$offer->offer_message}}</li>
    @endforeach
    </ul>
@endforeach 
Melodia

No no, this will give the wrong data. Because an offer is placed by a different user, towards a property that is owned by another user. So, as the owner of the property, I want to ee all the offers placed towards my properties.

And just emphasize, I could see what I wanted in the return:

  • {{$property->offers}}
  • But only when I try to access a property that it doesnt work. Without mentioning that I see empty arrays.

    Snapey
    Snapey
    4 weeks ago (1,036,605 XP)

    @melodia well obviously you know best ?

    As you have a relationship from user;

    $properties = Auth::user()->properties()->with('offers')->get();
    

    $properties is now a collection of Property belonging to the user

    each Property will have a collection of offers.

    You have to iterate over the properties and for each property you can list out the offers

    For properties with no offer, you can say so rather that moaning here that you have empty arrays

    Melodia

    One of te things that I was failing to do is to loop through the offers collection;

    @if($properties)
    @php ($i = 1)
    <ul>
        @foreach($properties as $property)
                @foreach ($property->offers as $offer)
                    <li>Offer {{ $i++ }}: {{$offer->offer_message}}</li>
                @endforeach
        @endforeach
    </ul>
    @endif
    

    Then in the controller I did this as both @Cronix and @Snapey logic suggested:

    $properties = Property::whereUserId(Auth::id())->has('offers')->get();
    

    Appreciate the support

    Snapey
    Snapey
    4 weeks ago (1,036,605 XP)

    You still need to do ->with('offers') otherwise you will have n+1 issue in your foreach over the offers (a db query for every offer)

    Please sign in or create an account to participate in this conversation.