Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lravel 5.4 : get products with favorite and display favorites product for each user

I am trying to get all products with favorite and display them as if user logged in and this products in favorite it will appear as favorite else he can add them to favorite.

here is my controller

$products = ( new Product )
            ->where( 'quantity', '>', 0 )
            ->with( 'favorite' )
            ->orderBy( 'price', $sort )->get();

now if I make dd($product->favorite) I get the favorite array like so

[{"id":1,"product_id":7,"user_id":1,"created_at":"2018-04-01 09:16:23","updated_at":"2018-04-01 09:16:23"}]

but if I try to select any of this array like {{ $product->favorite->product_id }}

I get

Property [product_id] does not exist on this collection instance

How I display in blade

    @foreach($products as $product)
            <div class="col-md-4 col-sm-6">
                 <div class="thumbnail no-border no-padding">
                      <div class="media">
                      <a class="media-link" href="{!! URL::route('products.show', $product->id) !!}">
                      {!! Html::image('images/products/'.$product->image, $product->name) !!}
                      <span class="icon-view">
                      <strong><i class="fa fa-eye"></i></strong>
                      </span>
                      </a>
                     </div>
                     <div class="caption text-center">
                          <h4 class="caption-title">{!! $product->name !!}</h4>

                         <div class="price">
                         <ins>{!! $product->price !!}</ins>
                         {{--<del>$425.00</del>--}}
                         </div>
                         {{ $product->favorite->product_id }}
                      <div class="buttons">
                     @if(count($product->favorite) == 1)
                      <span class="btn btn-theme btn-theme-transparent">
                      <i class="fa fa-heart text-danger"></i>
                     </span>
                     @else
                     {!! Form::open(['route'=>'favorite.store', 'class'=>'favorite-products']) !!}
                     {!! Form::hidden('product_id', $product->id) !!}
                     @if ( Auth::guard( 'web' )->check() != 0 )
                     {!! Form::hidden('user_id', Auth::guard( 'web' )->user()->id) !!}
                     @endif
                     <button class="btn btn-theme btn-theme-transparent btn-wish-list">
                     <i class="fa fa-heart"></i>
                     </button>
                     @endif


                    {!! Form::close() !!}


                  {!! Form::open(['route'=>'add.to.cart', 'class'=>'btn product-shoppingcart-icon']) !!}
                 {!! Form::hidden('pro_id', $product->id) !!}
                 <button class="btn btn-theme btn-theme-transparent btn-icon-left">
                 <i class="fa fa-shopping-cart"></i>{{ trans('interface.addToCart') }}
                 </button>
                {!! Form::close() !!}
                <a class="btn btn-theme btn-theme-transparent btn-compare"
                href="#"><i class="fa fa-exchange"></i></a>
                </div>
              </div>
        </div>
    </div>
@endforeach
like image 771
Yousef Altaf Avatar asked Jan 29 '26 23:01

Yousef Altaf


1 Answers

I think that the current query is inefficient. As far as I understand, a product can be liked by many users. If you then load all favorites for each product, you will also load favorites that are not relevant for the current user. You should therefore only select relevant favorites:

$products = Product::query()
    ->where('quantity', '>', 0)
    ->with(['favorite' => function ($hasMany) {
        $hasMany->where('user_id', \Auth::user()->id);
    }])
    ->orderBy('price', $sort)
    ->get();

You will then end up with a collection of favorites on each product, although there may only be at most one favorite in the collection (because the current user can like a product only once, right?). So you want to access the thing in your view with:

@foreach($products as $product)
    // ... your html here
    @if(count($product->favorite))
        <span class="btn btn-theme btn-theme-transparent">
            <i class="fa fa-heart text-danger"></i>
        </span>
    @endif
    // ... more html
@endforeach

Explanation: $product->favorite is a collection and count() will therefore give you the number of items. As there can be none or one favorite for the current user, we either receive 0 or 1 as result, which can also be seen as false and true respectively.


Edit: To avoid issues with not logged in users, you can use this query, which will simply not load the favorite relation then.

$products = Product::query()
    ->where('quantity', '>', 0)
    ->orderBy('price', $sort)
    ->when(\Auth::check(), function ($query) {
        $query->with(['favorite' => function ($hasMany) {
            $hasMany->where('user_id', \Auth::user()->id);
        }]);
    })
    ->when(\Auth::guest(), function ($query) {
        $query->with(['favorite' => function ($hasMany) {
            // will exclude all rows but flag the relation as loaded
            // and therefore add an empty collection as relation
            $hasMany->whereRaw('1 = 0');
        }]);
    })
    ->get();

Or in case someone doesn't like the weird database call that will always return zero rows, we can also set the relation manually:

$products = Product::query()
    ->where('quantity', '>', 0)
    ->orderBy('price', $sort)
    ->when(\Auth::check(), function ($query) {
        $query->with(['favorite' => function ($hasMany) {
            $hasMany->where('user_id', \Auth::id());
        }]);
    })
    ->get();

if (\Auth::guest()) {
    $products->each(function ($product) {
        $product->setRelation('favorite', new \Illuminate\Database\Eloquent\Collection());
    });
}
like image 59
Namoshek Avatar answered Jan 31 '26 17:01

Namoshek