Dev Talks

Web Development Tutorials

Laravel REST API Part 2: Create Migrations, Models, and Factories
Laravel

Laravel REST API Part 2: Create Migrations, Models, and Factories

Published on Nov 19, 2024

In this tutorial, we’ll walk through creating models, migrations, for our Laravel API. and we will populate some data as well with factories and seeders to be able to test our api's.


Setting Up Models and Migrations


Database Design Overview

  • users: We have already predefined migration file with users table, so we will not worry about it.
  • categories: We could have the following columns [id, name].
  • products: We might have [id, name, price, stock, category_id]
  • orders: With the following columns [id, user_id, total_price, status]
  • order_product: A pivot table for the many-to-many relationship between orders and products, with fields [id, order_id, product_id, quantity]


Creating Models and Migrations

Run the following commands to create the models and migrations:

php artisan make:model Category -m  
php artisan make:model Product -m  
php artisan make:model Order -m 

The -m flag generates migration files automatically.


Category Migration

In the create_categories_table.php migration file:

Schema::create('categories', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->timestamps();
});


Product Migration

In the create_products_table.php migration file:

Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->decimal('price', 10, 2);
    $table->integer('stock')->default(0);
    $table->foreignId('category_id')->constrained()->cascadeOnDelete();

    $table->timestamps();
});


Order Migration

In the create_orders_table.php migration file:

Schema::create('orders', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constraned()->cascadeOnDelete();
    $table->decimal('total_price', 10, 2)->default(0);
    $table->tinyInteger('status')->default(0);
    $table->timestamps();
});

Schema::create('order_product', function (Blueprint $table) {
    $table->id();
    $table->foreignId('product_id')->constraned()->cascadeOnDelete();
    $table->foreignId('order_id')->constraned()->cascadeOnDelete();
    $table->integer('quantity')->default(1);
    $table->timestamps();
});


Alongside with the orders migration we added order_product in same file because they are related and we will not have a model for it. So no need to create a separate file for it

And don't forget to add this line in down function:

Schema::dropIfExists('order_product');



Defining Model Relationships


Category Model

In Category.php:

use Illuminate\Database\Eloquent\Relations\HasMany;

protected $fillable = ["name"];

public function products(): HasMany
{
   return $this->hasMany(Product::class);
}


Product Model

In Product.php

use Illuminate\Database\Eloquent\Relations\BelongsTo;

protected $fillable = [
    'name',
    'price',
    'stock',
    'category_id',
];

public function category(): BelongsTo
{
    return $this->belongsTo(Category::class);
}


Order Model

in Order.php

use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

protected $fillable = [
    'user_id',
    'total_price',
    'status',
];

public function user(): BelongsTo
{
    return $this->belongsTo(User::class);
}

public function products(): BelongsToMany
{
    return $this->belongsToMany(Product::class);
}



Creating Factories


Category Factory

Generate the factory:

php artisan make:factory CategoryFactory

In CategoryFactory.php in definition function:

return [
    'name' => fake()->word(),
];


Product Factory

Generate the factory:

php artisan make:factory ProductFactory

In ProductFactory.php

return [
    'name' => fake()->words(4, true),
    'price' => fake()->numberBetween(10, 500),
    'stock' => fake()->numberBetween(0, 50)
];


Update Models

We need also to update our models to be able to use those factories:

In Category.php model we need to add HasFactory trait

use Illuminate\Database\Eloquent\Factories\HasFactory;

/** @use HasFactory<\Database\Factories\CategoryFactory> */
use HasFactory;

You need to do the same with Product model as well


DatabaseSeeder

In the DatabaseSeeder.php we need to seed our data using factories we just added, you might create a separate seeder file for each model, but our setup is very basic, so no need for separate files.

Category::factory()->count(5)->hasProducts(50)->create();

With this simple line we will be able to create 5 categories each category should have 50 product, which will be good enough to be able to test our api's.



Run Migrations and Seeder


We will use the following command to add migrations table and seeder data to our database

php artisan migrate --seed


We should be done, you can verify by checking the data via SQLite viewer extension if you installed it.


Conclusion 

We are done with our basic setup in the previous article and in this article we added our tables and data we are going to need.

In the next article we will begin to add our api's and we will start with authentication.