32

I'm stuck on this what seems like a simple task.

I have a User that has many Shops that have many Products..

I'm trying to get all the Products for a certain User.

This is working, and is returning the Shops with their Products

\Auth::user()->shops()->with('products')->get();

But I need a Collection of only the Products. I tried the following but it's messing up the Query

\Auth::user()->shops()->with('products')->select('products.*')->get();

Any idea what I'm doing wrong? Thank you!

Miguel Stevens
  • 8,631
  • 18
  • 66
  • 125
  • 2
    What's wrong with doing `Products::where('user_id', Auth::id())->get()`? Do you need access to the shops also? – haakym May 11 '17 at 08:20

4 Answers4

75

You can use this :

\Auth::user()->shops()->with('products')->get()->pluck('products')->flatten();

if you don't want replicate, you can use ->unique()

If you want to directly work on a query (for performances):


 Product::whereHas('shops', function($query){
    $query->where('user_id', auth()->user()->id);
 })->get();

Mathieu Ferre
  • 4,246
  • 1
  • 14
  • 31
14

what you need is a relationship between the User Model and the Product Model ..

this is possible using hasManyThrough relationship ..

USER MODEL

public function products()
{
    return $this->hasManyThrough('App\Product', 'App\Shop')
}

now, you can access all the user's products with

Auth::user()->products;
Demonyowh
  • 1,673
  • 1
  • 9
  • 14
  • Thanks for your answer. The problem is, there will also be Users that are a Supplier in, and don't have Shops.. So that will conflict then right. – Miguel Stevens May 11 '17 at 08:14
  • 1
    then in your case .. your product model should have also have a user_id field in the database .. then change the return to `$this->hasMany('App\Product'); but this is not a good practice as you are bypassing the hierarchy of your model relations .. – Demonyowh May 11 '17 at 08:17
  • Worth noting you can use ->with('relationship') to eager load that relationship – Daniel Waters Jul 26 '17 at 14:11
6

In this case you can use lazy eager loading:

auth()->user()->load('shops.products');

To iterate over products:

@foreach (auth()->user()->shops as $shop)
    @foreach ($shop->products as $product)
        {{ $product->name }}
    @endforeach
@endforeach

If you need just products:

Product::whereHas('shop', function ($q) {
    $q->where('user_id', auth()->id());
})->get();

In both cases, you'll have the same number of queries to DB, so I'd use the first example in a real app.

Alexey Mezenin
  • 158,981
  • 26
  • 290
  • 279
  • im not the one who downvoted this but i think this is because the OP is asking how to access products without using the shop .. – Demonyowh May 11 '17 at 08:14
  • @Demonyowh your example creates queries for using `shops` table too, so it uses shops anyway. – Alexey Mezenin May 11 '17 at 08:15
  • @Notflip I've added another solution that uses `shop` relationship which is `belongsTo()` in the `Product` model. – Alexey Mezenin May 11 '17 at 08:23
  • @Demonyowh as you can see I've said about the queries in my comment. BTW, in a real app, you'll need shops sooner or later. – Alexey Mezenin May 11 '17 at 08:23
  • im not the one who downvoted this .. it's just my assumptions .. i dont know why they downvoted this .. sorry .. – Demonyowh May 11 '17 at 08:24
  • Your non-edited answer did not include the `whereHas` example. And the question asks for `the collection of ONLY the products`. If you load the shops of the users and the products of the shops, you will end up with a User object which has a Collection of shops and every shop with their separate product collections. That is not what the question asks. That is why I down voted your answer. – Hilmi Erdem KEREN May 11 '17 at 08:36
-2

Assuming that your product model has the shop id stored, try the following:

Products::whereIn('id_shop',
    Shops::select('id')
    ->where('id_owner_user',Auth::user()->id)
    ->get())
->get()

It will retrieve a collection of products that belong to the list of shops which belong to the authenticated user

aaron0207
  • 2,293
  • 1
  • 17
  • 24
  • This doesn't use relationships or a join, this is just two SELECT queries one run inside the other as a parameter so is less efficient and not what OP asked – Daniel Waters May 11 '17 at 08:05
  • He said: "But I need a Collection of only the Products." if you make a join you are pulling two models – aaron0207 May 11 '17 at 08:07
  • 1
    BTW, for those who downvoted, laravel relationships produce a query like mine and @DanielWaters I was reading today a lot about it and two select queries are faster than a join. Have a good coding mates – aaron0207 May 11 '17 at 16:01