Crinsane / LaravelShoppingcart

A simple shopping cart implementation for Laravel
MIT License
3.67k stars 1.73k forks source link

Associate Model with Relationship #96

Closed yansentan closed 8 years ago

yansentan commented 9 years ago

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();

amirmasoud commented 9 years ago

you mean associate to 2 models? if it's 2 models I will add second model data as option.

cmoralesweb commented 9 years ago

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()

lukepolo commented 8 years ago

Dang this would be cool.

petraeus commented 8 years ago

You can access relationships via the associated model if that model has the proper HasOne, hasMany etc relations coded into it.

skoellen commented 6 years ago

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.

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.

GordanaP commented 6 years ago

@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')