theUnforgiven's avatar

[L4] E-Commerce question, about products...

I've posted about this before but thought it would be better posting again as I've made a couple of changes to certain area's, plus I didn't want to go through everything again and everyone get mixed up. So here goes.....

I've built a custom e-commerce site that sells clothing, each clothing item has colour, size and stock in the product_options table, like so:

Then the related product it'self is:

Now this works but it shows available colours even though stock is set to zero/0 which isn't right you need to select a colour once then some JS looks up the product_options table to send back this info as a JSON response.

Like so:

$(function(){

                $('.colors').on('change', function(e){
                    var cat_id = e.target.value;
                    var current = $(this).data("index");

                    var select = $("select[data-index='"+current+"'][class='sizes']");

                    $.get('/related-sizes?info=' + cat_id, function(data){
                        select.empty();
                        $.each(data, function(index, subcatObj){
                            select.append('<option value="'+subcatObj.size+'">'+subcatObj.size+'</option>');
                        });
                    });
                });
                var a = new Array();
                $(".colors").children("option").each(function(x){
                    test = false;
                    b = a[x] = $(this).val();
                    for (i=0;i<a.length-1;i++){
                        // if (b ==a[i]) test =true;
                        if (b ==a[i] && b != '') test =true;
                    }
                    if (test) $(this).remove();
                });
            });

Which gets sent to this method:

public function selectedColour()
    {

        $info = explode('-', Input::get('info'));
        $cat = Options::where('product_id', $info[0])
            ->where('colour', $info[1])
            ->orderBy('size', 'asc')
            ->get(['id', 'size', 'colour', 'stock']);
        return Response::json($cat, 200);
    }

This is the underlining HTML

<div class="product-details">
                        @if($item->availableColours() && $item->availableStock())
                            Colour
                            <select name="colour" class="colors" data-index="{{ $item->id }}">
                                <option value="" selected="selected">Please Select</option>
                                @foreach($item->options as $option)
                                    <option value="{{ $option->product_id }}-{{ $option->colour }}">{{ $option->colour }}</option>
                                @endforeach
                            </select>
                        @endif
                        <br />
                        @if($item->availableSizes())
                            Size:
                            <select name="size" class="sizes" data-index="{{ $item->id }}">
                                <option value=""></option>
                            </select>
                        @endif
                    </div>

The Product Model:

public function options()
    {
        return $this->hasMany('Options','product_id', 'id');
    }

    public function availableColours()
    {
        return $this->options()->select('colour')->distinct()->where('stock', '>', 0)->lists('colour');
    }

    public function availableSizes()
    {
        return $this->options()->select('size')->distinct()->where('stock', '>', 0)->lists('size');
    }

    public function availableStock()
    {
        return $this->options()->select('stock')->distinct()->where('stock', '>', 0)->lists('stock');
    }

So I need some way to check it has stock of at least 1 to be returned and only show each colour in the first select menu once. Can someone please help me with this?

Thanks in advance :)

0 likes
40 replies
theUnforgiven's avatar

If I select "black" I know from the db that the size "14-16" is the only one that has stock, but yet shows all three sizes.

DB:

theUnforgiven's avatar

I had a good read through the docs and f**k me I found

->having('stock', '>', 0)

So added that to the "selectedColour" method and now works kinda, but if i have colours black, white & green with only black size 14-16 with some stock the other colours still show, how can make this only show colours with stock.

theUnforgiven's avatar

So in this example the colour select/drop down should only show Black, has black is the only colour that as an item with stock more than zero

Currently showing like this which isn't right.

theUnforgiven's avatar

Anyone know based on everything I have posted and talked about how I can do this?

theUnforgiven's avatar

Still showing incorrectly need a second pair of eyes on this if someone can help

graham's avatar

In your product details don't you need populate the options with availableColours rather than colour?

theUnforgiven's avatar

Not sure what you mean, i have:

 @if($item->availableColours() && $item->availableStock())
                                Colour
                                <select name="colour" class="colors" data-index="{{ $item->id }}">
                                    <option value="" selected="selected">Please Select</option>
                                    @foreach($item->options as $option)
                                        <option value="{{ $option->product_id }}-{{ $option->colour }}">{{ $option->colour }}</option>
                                    @endforeach
                                </select>
                            @endif
graham's avatar

So you're only showing products that have stock for the available colour but it's displaying all colours here:

<option value="{{ $option->product_id }}-{{ $option->colour }}">{{ $option->colour }}</option>

$option->colour needs to only list available colours rather than all colours, is that right?

Something along these lines:

<option value="{{ $option->product_id }}-{{ $option->availableColours }}">{{ $option-> availableColours }}</option>
graham's avatar

Something like:

<option value="{{ $option->product_id }}-{{ $option->availableColours->colour }}">{{ $option-> availableColours->colour }}</option>
graham's avatar

arrrgggghhhh :-) this is driving me mad

You're foreach looping through @foreach($item->options as $option) so options must be returning colours that aren't available. I wonder if something like @foreach($item->options->availableColours as $option)

Or would you be better with an additional method that only returns availableOptions

theUnforgiven's avatar

Undefined property: Illuminate\Database\Eloquent\Collection::$availableColours when doing @foreach($item->options->availableColours as $option) so i guess an additional method would be better, just not sure how :( I know its driving me crazy too

graham's avatar

I'm still thinking we might be able to use availableColours somehow.

<option value="{{ $option->product_id }}-{{ $option->availableColours }}">{{ $option-> availableColours }}</option>

or

<option value="{{ $option->product_id }}-{{ $option->availableColours() }}">{{ $option-> availableColours() }}</option>
theUnforgiven's avatar

The first option doesn't display anything and the second option display a relationship error

frezno's avatar

That's why i don't all this Mambo Jambo (on the fly list) although, i have to admit, it's nice.

I'm doing it the good ol' way showing all products available either in a dropdown list or listed with radio buttons. Three options: Item in stock, out of stock, but will get in soon, no more available.

Although i usually don't like to mix more options, ie there's a shirt in red, availble in sizes S-XXl, another shirt sizes S-XXL etc. don't like: this shirt is availble in red, green, yellow and in sizes S-XXL, etc.

graham's avatar

I just spotted a couple of erroneous spaces in my $option-> availableColours(), count that will make a big difference though.

graham's avatar

Back to the new method plan, something like:

public function optionsWithAvailableColours()
{
    return $this->hasMany('Options','product_id', 'id')->select('colour')->distinct()->where('stock', '>', 0)->lists('colour');
}
theUnforgiven's avatar

arrrrggghhhh

Call to undefined method Illuminate\Database\Query\Builder::optionsWithAvailableColours() 
graham's avatar

lol, where is that method? Can you share your product model?

theUnforgiven's avatar
class Products extends \Eloquent {

    protected $guarded = ['id'];

    public function categories()
    {
        return $this->belongsTo('Categories');
    }

    public function options()
    {
        return $this->hasMany('Options','product_id', 'id');
    }

    public function availableColours()
    {
        return $this->options()->select('colour')->distinct()->where('stock', '!=', 0)->lists('colour');
    }

    public function availableSizes()
    {
        return $this->options()->select('size')->distinct()->where('stock', '!=', 0)->lists('size');
    }

    public function availableStock()
    {
        return $this->options()->select('stock')->distinct()->where('stock', '!=', 0)->lists('stock');
    }

    public function optionsWithAvailableColours()
    {
        return $this->hasMany('Options','product_id', 'id')->select('colour')->distinct()->where('stock', '>', 0)->lists('colour');
    }

}
graham's avatar

what about the html/blade

something like:

<select name="colour" class="colors" data-index="{{ $item->id }}">
        <option value="" selected="selected">Please Select</option>
        @foreach($item->optionsWithAvailableColours as $option)
            <option value="{{ $option->product_id }}-{{ $option->colour }}">{{ $option->colour }}</option>
        @endforeach
   </select>
theUnforgiven's avatar

Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation

graham's avatar

ok, scratch those.

Can you try and die & dump options and availableColours so we can see what's being passed to the page.

theUnforgiven's avatar

dd outputs

array (size=1) 0 => string 'Black' (length=5)

1 like
theUnforgiven's avatar

but it needs to be $item->options as I'm using the options relationship

Next

Please or to participate in this conversation.