Laravel E-Commerce Application Development – Products Section Part 1

Laravel E-Commerce Application Development – Products Section Part 1

Laravel E-Commerce Application Development ( 27 Lessons )

In this course, you’ll learn how to create an E-Commerce Website from scratch in Laravel. The process has never been easier I’ll take you from the very beginning stages of setting up Laravel till the last steps of adding products to the cart. If you’ve good understanding & experience in PHP & MySQL then this course is for you.

see full series
  1. Laravel E-Commerce Application Development – Introduction
  2. Laravel E-Commerce Application Development – Initial Project Setup
  3. Laravel E-Commerce Application Development – Assets Setup Using Laravel Mix
  4. Laravel E-Commerce Application Development – Admin Model and Migration
  5. Laravel E-Commerce Application Development – Backend Admin Authentication
  6. Laravel E-Commerce Application Development – Base Controller and Repository
  7. Laravel E-Commerce Application Development – Settings Section Part 1
  8. Laravel E-Commerce Application Development – Settings Section Part 2
  9. Laravel E-Commerce Application Development – Categories Section Part 1
  10. Laravel E-Commerce Application Development – Categories Section Part 2
  11. Laravel E-Commerce Application Development – Attributes Section Part 1
  12. Laravel E-Commerce Application Development – Attributes Section Part 2
  13. Laravel E-Commerce Application Development – Attributes Section Part 3
  14. Laravel E-Commerce Application Development – Brands Section
  15. Laravel E-Commerce Application Development – Products Section Part 1
  16. Laravel E-Commerce Application Development – Products Section Part 2
  17. Laravel E-Commerce Application Development – Products Section Part 3
  18. Laravel E-Commerce Application Development – Products Section Part 4
  19. Laravel E-Commerce Application Development – Frontend Login & Registration
  20. Laravel E-Commerce Application Development – Categories Navigation
  21. Laravel E-Commerce Application Development – Catalog Listing
  22. Laravel E-Commerce Application Development – Product Details Page
  23. Laravel E-Commerce Application Development – Shopping Cart
  24. Laravel E-Commerce Application Development – Checkout
  25. Laravel E-Commerce Application Development – Payment Processing
  26. Laravel E-Commerce Application Development – Order Management
  27. Laravel E-Commerce Application Development – Wrap Up

This is part 14 of the Laravel E-Commerce Application Development series. In this part, we will add the models and migrations for Product.

Planning

In this post, we will look at how we can store the products in our database. It’s absolutely necessary to plan ahead before jumping into the products section.

Here are some features, which we would like to implement in our products.

  • A product will belong to a Brand.
  • A product will belong to many categories and a category will have many products.
  • As we know most of the eCommerce websites display multiple images for a product. So we need to have a model for images, then we can define a product have many images features.
  • A product also can have many attributes with different quantity and price.

Keeping all above in mind, we will proceed to create the necessary models and migration for Products section.

Product Model and Migration

First of all, we need a Product model. Head over to your command line terminal and run the below command to generate the model and migration for Product.

php artisan make:model Models\Product -m

Above command will generate a model in app/Models folder and a migration file in database/migrations folder.

Open the migration file and update with the below one.

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateProductsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedInteger('brand_id')->index();
            $table->string('sku');
            $table->string('name');
            $table->string('slug');
            $table->text('description')->nullable();
            $table->unsignedInteger('quantity');
            $table->decimal('weight', 8, 2)->nullable();
            $table->decimal('price', 8, 2)->nullable();
            $table->decimal('sale_price', 8, 2)->nullable();
            $table->boolean('status')->default(1);
            $table->boolean('featured')->default(0);

            $table->foreign('brand_id')->references('id')->on('brands')->onDelete('cascade');

            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('products');
    }
}

As you can see, we have defined the different columns for our product each with a relevant data type. Pay special attention to the brand_id column with the foriegn key, using this column we can relate the Product model with Brand model.

Next, open the Product model calls from app/Models folder and update with the below one.

namespace App\Models;

use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    /**
     * @var string
     */
    protected $table = 'products';

    /**
     * @var array
     */
    protected $fillable = [
        'brand_id', 'sku', 'name', 'slug', 'description', 'quantity',
        'weight', 'price', 'sale_price', 'status', 'featured',
    ];

    /**
     * @var array
     */
    protected $casts = [
        'quantity'  =>  'integer',
        'brand_id'  =>  'integer',
        'status'    =>  'boolean',
        'featured'  =>  'boolean'
    ];

     /**
     * @param $value
     */
    public function setNameAttribute($value)
    {
        $this->attributes['name'] = $value;
        $this->attributes['slug'] = Str::slug($value);
    }


    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function brand()
    {
        return $this->belongsTo(Brand::class);
    }
}

In the Product model, we defined the table and fillable property. In the $casts property, we casted some field with the proper data types. Next, we defined the brand() method which return an instance of belongsTo class and establish the One To Many relationship between Product and Brand.

Now open the Brand model and add the below method in it.

/**
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function products()
{
    return $this->hasMany(Product::class);
}

In this method, we simply defined the One To Many relationship so a brand can have many products.

Product Images Model and Migration

In this section, we will add the model and migrations for product images. As a product can have multiple images, so we will host the images in a separate table. Open your terminal and hit the below command to generate the model and migrations.

php artisan make:model Models\ProductImage -m

Now, open the migration file generated for product images and update with the below one.

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateProductImagesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('product_images', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedInteger('product_id')->index();
            $table->string('thumbnail')->nullable();
            $table->string('full')->nullable();

            $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('product_images');
    }
}

In the product_images table, we add the two fields to store images one for thumbnail and one full-size image. Also, we added the product_id column with the foreign key, which will establish the relationship between product and product images table.

Now open the ProductImage model and update with the below one.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class ProductImage extends Model
{
    /**
     * @var string
     */
    protected $table = 'product_images';

    /**
     * @var array
     */
    protected $fillable = ['product_id', 'thumbnail', 'full'];

    /**
     * @var array
     */
    protected $casts = [
        'product_id'    =>  'integer',
    ];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function product()
    {
        return $this->belongsTo(Product::class);
    }
}

In this model, we added a product() method which will return a belongsTo relationship. Now, we will update the Product model and add the below method in it.

/**
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function images()
{
    return $this->hasMany(ProductImage::class);
}

The images() method will return a hasMany relationship, so we can have more than one images for a product.

Product Attributes Model and Migrations

Now, we will link the attributes to products. This section is a bit tricky, so please pay special attention.

So the plan is to create a new model with table named ProductAttribute which will have the product id to link it with product, then we will create a pivot table to link this product_attributes table with the attribute_values. There are many implementations of adding attributes for a product, but I found this one easy and will get the job done.

Open your terminal and run the below command.

php artisan make:model Models\ProductAttribute -m

Now open the ProductAttribute migration file from database/migrations folder and update with the below one.

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateProductAttributesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('product_attributes', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('quantity');
            $table->decimal('price')->nullable();
            $table->unsignedInteger('product_id');
            $table->foreign('product_id')->references('id')->on('products');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('product_attributes');
    }
}

In this table we added the quantity and price for each attribute value and then added the product_id with the foreign key.

Side Note

You might be wondering, we already have the quantity column in products table, so why have it in the product attributes table.
The only reason for defining the quantity in both tables is, there can be some products which don’t have attributes. So we can use the quantity column from the products table. Hope, I cleared the point.

Now open the ProductAttribute model and update with the below one.

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class ProductAttribute extends Model
{
    /**
     * @var string
     */
    protected $table = 'product_attributes';

    /**
     * @var array
     */
    protected $fillable = ['product_id', 'quantity', 'price'];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function product()
    {
        return $this->belongsTo(Product::class);
    }
}

In this we defined the product() method to relate this model instance to the Product model.

Next, in your Product model add the below method.

/**
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function attributes()
{
    return $this->hasMany(ProductAttribute::class);
}

Above method will return the attributes for a given product using hasMany relationship.

So far so good!

Now, we need to create a pivot table to link ProductAttribute with the AttributeValue.

The whole reason for taking this approach is to access the attribute values with different price and quantity for a given product.

So open your terminal, and run the below command.

php artisan make:migration create_attribute_value_product_attribute_table

Open newly created migration file and update with the below one.

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateAttributeValueProductAttributeTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('attribute_value_product_attribute', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedInteger('attribute_value_id');
            $table->foreign('attribute_value_id')->references('id')->on('attribute_values');
            $table->unsignedInteger('product_attribute_id');
            $table->foreign('product_attribute_id')->references('id')->on('product_attributes');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('attribute_value_product_attribute');
    }
}

In this migration we have defined two columns attribute_value_id and product_attribute_id along with the the foriegn keys on attribute_values and product_attributes respectively.

So now we can update the ProductAttribute model, open ProductAttribute model and add the below method in it.

/**
 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
 */
public function attributesValues()
{
    return $this->belongsToMany(AttributeValue::class);
}

Here, we are defining the Many To Many relationships between the ProductAttribute and AttributeValue models.

Now open the AttributeValue model and add the below method in it.

/**
 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
 */
public function productAttributes()
{
    return $this->belongsToMany(ProductAttribute::class);
}

That’s it for the product attributes. ?

Updating Category Model

One last thing left is to link the categories with the product. ?

Don’t worry it will be similar to what we did in the last section.

So open your terminal one last time ?, and run the below command.

php artisan make:migration create_product_categories_table

Now open this migration file and update with the below one.

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateProductCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('product_categories', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->integer('category_id')->unsigned()->index();
            $table->foreign('category_id')->references('id')->on('categories');
            $table->integer('product_id')->unsigned()->index();
            $table->foreign('product_id')->references('id')->on('products');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('product_categories');
    }
}

Now, open the Category model and add the below method in it.

/**
 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
 */
public function products()
{
    return $this->belongsToMany(Product::class, 'product_categories', 'category_id', 'product_id');
}

Next, open the Product model and add the below method.

/**
 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
 */
public function categories()
{
    return $this->belongsToMany(Category::class, 'product_categories', 'product_id', 'category_id');
}

Now in our application, a product can have many categories and a category can have many products.

Migration Tables

Now, simply run the php artisan migrate command to create all tables, whenever you are fancy.

Great ??

Conclusion

That’s it for now, in the next post we will start creating the products section for our admin area.

Products section is one of the most important and will be a tricky one in term on attributes, so I have divided this section into two part.

Code Repository

You can find the code base of this series on Laravel eCommerce Application repository.

If you have any question about this post, please leave a comment in the comment box below and I will try my best to answer your questions.

Your little help will keep this site alive and help us to produce quality content for you.