Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

theUnforgiven's avatar

Multiple Stock Columns

I have a database that has 7 stock columns as each product has a different size, colour and stock.

So what I want to do is pass this data through using the moltin laravel cart package which I'm using put then minus 1 off the stock for whichever ever item has been sold.

For example: I have a t-shirt that has 3 sizes S, M, L and the small as a stock of 3, the medium as stock of 5 and large as stock of 1. A customer comes to the site buys the large t-shirt so i need to know what the best way would be to get this and then set to the stock to zero has there's only the 1 stock of the large t-shirt but not touch the stock of the other two t-shirts until they are sold.

What is the best way to do this?

I'm already getting the product like so: $product = Products::find($id); but how can I check what the item is has it's all on one row.... Hope that makes sense and someone can help me like you @bashy

0 likes
44 replies
bart's avatar

Could you please give more information about your database design? How are your product attributes stored? What are the relations?

bart's avatar

Wouldn't it be better to split this into multiple tables like one for sizes, one for stocks and one for prices?

There are a lot of possibilities to answer this. The question is what do you get from your form when somebody buys a product. If you get "size_4" you can substring the size "4" and do:

// You have "4" as $size and 12 as product ID from you form
$product = Product::find(12);
// Don't really sure if it works, maybe you have to replace this by $product->stock_$size = $product->stock_$size - 1;
$product->stock_$size--;
$product->save();

But imo this really is dirty. You should split information in your database to get a more cleaner way. Then you could do sth like:

// $this->product has been injected by using Laravels dependency injection in your constructor (its just a repository)
$this->product->decreaseStockforSize(4);
theUnforgiven's avatar

Yes each form element has a name of size_1 then has stock_1 size_2 then stock_2 relevant to what they are buying. so need to minus whichever is bought.

theUnforgiven's avatar

Still having trouble with this, not updating the right stock item, what @bart said doesn't work and am not sure how i can get the the right stock value to update it as it's all in the same db row.

theUnforgiven's avatar

Would it be better if i created 3 new migrations like so:

Schema::create('product_colours', function(Blueprint $table)
        {
            $table->increments('id');
            $table->integer('product_id');
            $table->string('colour');
            $table->string('colour_1');
            $table->string('colour_2');
            $table->string('colour_3');
            $table->string('colour_4');
            $table->string('colour_5');
            $table->string('colour_6');
        });
Schema::create('product_sizes', function(Blueprint $table)
        {
            $table->increments('id');
            $table->integer('product_id');
            $table->string('size');
            $table->string('size_1');
            $table->string('size_2');
            $table->string('size_3');
            $table->string('size_4');
            $table->string('size_5');
            $table->string('size_6');
        });
Schema::create('product_stock', function(Blueprint $table)
        {
            $table->increments('id');
            $table->integer('product_id');
            $table->string('stock');
            $table->string('stock_1');
            $table->string('stock_2');
            $table->string('stock_3');
            $table->string('stock_4');
            $table->string('stock_5');
            $table->string('stock_6');
        });

Would it make it better to use relationships then subtracting stock would be easier to do?

arabsight's avatar

Your schema design is not normalized, You can at least create 2 table: Products and ProductProperties

Products
  id
  name


ProductProperties
  id
  product_id
  size
  color
  stock

You can even normalize it further.

arabsight's avatar

Sure every record in the Products table has many records in the ProductsProperties table,

bashy's avatar

Shouldn't you have a pivot for attached sizes and colours for each product?

theUnforgiven's avatar

@bashy - Thats the question, i'm looking for the best way to do this as you can see from the schema above there's multiple stock, size and colours for each product, so wondering the best way.... Advice?

bart's avatar

As I already told you splitting the table into multiple one like you did by creating 3 migrations should be perfect. But as @arabsight said the normalized way are two tables like products and properties. Then you can fetch the corresponding entry by ID and decrease its stock.

theUnforgiven's avatar

What does 'normalized way are two tables like products and properties' mean whats a normalized way?

arabsight's avatar

Normalization is the process of efficiently organizing data in a database. There are two goals of the normalization process: eliminating redundant data (for example, storing the same data in more than one table ) and ensuring data dependencies make sense (only storing related data in a table). Both of these are worthy goals as they reduce the amount of space a database consumes and ensure that data is logically stored.

Its like design patterns for databases. First Normal Form: eliminate duplicative columns from the same table. the Size1-Size4, ... columns are duplicative.

bart's avatar

Normalized in that case means that you don't have empty fields (simply spoken). Every size-color pair has a stock amount. So you can do something like this:

$properties = Product::with('properties')->whereProductId($productId)->whereSize('s')->whereColor('black');
$properties->stock--;
$properties->save();
theUnforgiven's avatar

So doing the schema i suggested would work then is that what you telling me?

bart's avatar

But @lstables you can create a new entry for each set:

// products table
id     name
1      tshirt
2      socks
3      shoes

// properties table
id     product_id           size     color     stock
1       1                    S         black     4
2       2                    41       blue       7
3       1                    M        black     1
4       1                    M        green     0
5       3                    44        blue      10
6       3                    41        orange  1
7       2                    39        yellow  1
1 like
bart's avatar

Nope what we try to tell you is that you have to normalize your database table to have a more cleaner, performant and more simple to use one! Then you can use a method like the one I suggested above.

arabsight's avatar

Normalizing will make your life easier (adding new sizes and colours will be easy and you will not need to alter the table schema).

theUnforgiven's avatar

@bart I see now, yes makes sense that bloody hell, been having a complete brain freeze and getting mixed up but that is more efficient and makes sense.

theUnforgiven's avatar

Ok that works now but the form within the CMS has multiple options to add more than one product so how would I add that to this new product_options table.

Current code:

$option = new Options;
        $option->product_id = $product->id;
        $option->size = Input::get('size');
        $option->colour = Input::get('colour');
        $option->stock = Input::get('stock');
        $option->save();

But yet the form looks like so: http://cl.ly/image/1y0e050K1a22 so ideally needs to loop through and add the same product id mulitple time based on what's input any ideas @bart

theUnforgiven's avatar

if i dd() my inputs i get:

'size' => string '6' (length=1)
  'colour' => string 'Black' (length=5)
  'stock' => string '2' (length=1)
  'size_1' => string '10' (length=2)
  'colour_1' => string 'Cream' (length=5)
  'stock_1' => string '3' (length=1)
  'size_2' => string '0' (length=1)
  'colour_2' => string '0' (length=1)
  'stock_2' => string '' (length=0)
  'size_3' => string '0' (length=1)
  'colour_3' => string '0' (length=1)
  'stock_3' => string '' (length=0)
  'size_4' => string '0' (length=1)
  'colour_4' => string '0' (length=1)
  'stock_4' => string '' (length=0)
  'size_5' => string '0' (length=1)
  'colour_5' => string '0' (length=1)
  'stock_5' => string '' (length=0)
  'size_6' => string '0' (length=1)
  'colour_6' => string '0' (length=1)
  'stock_6' => string '' (length=0)
  'status' => string '0' (length=1)

so i need it to insert into product_options twice on this occasion has size and size_1, colour & colour_1 and stock & stock_1 have values

Ideally using this format and check to make sure its not empty or equals '0'

$option = new Options;
        $option->product_id = $product->id;
        $option->size = Input::get('size');
        $option->colour = Input::get('colour');
        $option->stock = Input::get('stock');
        $option->save();

So how would one achieve this ?

bashy's avatar

Haven't read all of this but to insert it only if it has a value is via the Input::get() default?

Input::get('size', null);

Or you can do some checks?

(Input::get('size') ?: null);
theUnforgiven's avatar

Its inserting the 1st result twice instead of the result been different values like i show above in the dd() but retain the same product_id

bashy's avatar

Do a foreach to make sure it works, then move it into a Product method so you can pass data to it and it will do it without the repeated code?

$product->addProductItems();
foreach ($items as $item)
{
    if ($foo == '')
    {
        //
    }
}

Yeah I'm lost, not sure what crazy functions you've got going on there :D

Next

Please or to participate in this conversation.