Closed yansentan closed 8 years ago
you mean associate to 2 models? if it's 2 models I will add second model data as option.
I'm interested in this functionality too. My models have several Relationships and queries get out of hand with just 2 products in the cart. I've tried using lazy eager loading ( http://laravel.com/docs/5.0/eloquent#eager-loading ), but since load() is a method of Database Collections and not Support Collections, method fails.
I've tried creating a new Database Collection from Cart::instance('main')->content() but I get this error
Call to undefined method Gloudemans\Shoppingcart\CartRowCollection::newQuery()
Dang this would be cool.
You can access relationships via the associated model if that model has the proper HasOne, hasMany etc relations coded into it.
If someone else comes here from search, I was testing around with this package and implemented a little workaround to reduce my queries when accessing cart-content and related information. Maybe this is helpful for someone:
In this example I have product_variants
that each belong to a product
.
Product
ProductVariant
I associated cartItems with my model ProductVariant
, where actual price and stock etc. is stored. But I also wanted to access global product information like "title", "description" etc. in my cart overview. This is where I got the query problem people already mentioned here.
Cart::content()
returns a collection, so I extracted the related / associated models and passed them separately to my view:
$cartItems = Cart::content();
// Get the ids from associated models of the cartItems
$ids = $cartItems->pluck('id');
// Here you can go wild on eager loading your relationships
$models = ProductVariant::with('product')->findMany($ids);
return view('cart-overview', ['cartItems' => $cartItems, 'models' => $models]);
In cart-overview.blade.php
:
@foreach($cartItems as $item)
<div class="panel panel-default">
<div class="panel-heading">
{{ $models->firstWhere('id', $item->id)->product->title }}
</div>
<div class="panel-body">
{{ $models->firstWhere('id', $item->id)->product->description }}
<hr>
{{ $item->price }}
</div>
<a href="/cart/delete-item/{{ $item->rowId }}">Delete from cart</a>
</div>
@endforeach
So I'm still looping over the cartItems within the view. But now with no additional queries (like e.g. $cartItem->model->product->title
). The information is already eager loaded and is connected via the model ids and firstWhere()
. And I can still use my cartItem information like $item->rowId
.
@skoellen Great work, thx.:) Association a cartItem with the 'App\Product' model results in so many duplicate queries! I followed your idea but had no need to use an intermediate model. My code is as following:
CartController.php
public function store (Request $request, Product $product)
{
Cart::add($product, $request->quantity, ['size' => $request->size]);
return back();
}
public function show()
{
$cartItems = Cart::content();
$ids = $cartItems->pluck('id');
$products = Product::findMany($ids);
return view('carts.show', compact('cartItems', 'products'));
}
carts\show.blade.php
@foreach ($cartItems as $item)
<div>
{{ $products->find($item->id)->name }}
{{ $products->find($item->id)->price }}
{{ $products->find($item->id)->description }}
{{ $item->options->size }}
{{ $item->rowId }}
{{ $item->qty }}
</div>
@endforeach
This way, my debug bar shows only one query:
select * from `products` where `products`.`id` in ('1', '2', '3')
If I have a 'Product' and 'ProductAttribute' model, and I want to get the data from the ProductAttribute model, how do I associate them both with associate()? Is it possible?
something like this Cart::associate('Product')->with('attribute')->add();