← Other topics

Laravel In a Nutshell - Database & Migrations (#5)

Series contents:

Video Notes

Laravel supports five different database types - MariaDB, MySQL, PostgreSQL, SQLite, SQL Server. In this guide, we’ll use MySQL.

Our goal will be to set up a database to manage our products and categories info that was previously hard-coded in an array:

$productsByCategory = [
    'health' => [
        'Band-Aids',
        'Johnson’s Baby Powder',
        'Tylenol'
    ],
    'tech' => [
        'GoPro Action Camera',
        'FitBit Fitness Watch',
        'Nintendo Switch'
    ],
    'books' => [
        'The Martian',
        'The Great Gatsby',
        'Joy Luck Club'
    ]
];

Here’s the structure of the resulting tables we’ll create: Resulting categories and products tables

To get started, you need a local database server so follow the appropriate instructions below...

Windows Users

Windows users working with Laragon (as set up in Part 1 of this series) don’t need to install any additional software because Laragon comes with a MySQL database service. Just confirm that your MySQL service is running along with your Apache web server.

Confirm MySQL is running via the Laragon control panel

With MySQL running, you can skip down to configuring the database in your Laravel app...

Mac Users

Mac users working with Herd (as set up in Part 1 of this series) can download the free program DBngin to run a MySQL database service.

Once downloaded, click the + icon to add a new service. Choose MySQL as the service type and give it a name (e.g. MySQL). Leave all the other options as their defaults and click Create.

Creating a new MySQL database service in DBngin

Once your new MySQL service is added click Start. A green circle will indicate the service is running:

New MySQL service running in DBngin

Configure database in your Laravel app

Next we need to configure our application to connect to the database services we set up above.

To do this, open your application’s environment file, .env located in the root of your project and find the settings prefixed with DB_:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

To work with DBngin and Laragon’s MySQL databases, you can leave most of these values as the default. The only thing you should change is DB_DATABASE - set this to the name you want to use for your database. In my example, I’ll change it to demo to match the name of my application.

With your configs set, run the command following command, which should prompt you to create your new database:

> php artisan migrate

Expected output:

   WARN  The database 'demo' does not exist on the 'mysql' connection.

 ┌ Would you like to create it? ────────────────────────────────┐
 │ ● Yes / ○ No                                                 │
 └──────────────────────────────────────────────────────────────┘

Choose yes and the migration will complete creating your new database as well as the default tables that come with every Laravel application:

  INFO  Preparing database.

  Creating migration table .......................................................... 48ms DONE

   INFO  Running migrations.

  2014_10_12_000000_create_users_table .............................................. 20ms DONE
  2014_10_12_100000_create_password_reset_tokens_table .............................. 13ms DONE
  2019_08_19_000000_create_failed_jobs_table ......................................... 9ms DONE
  2019_12_14_000001_create_personal_access_tokens_table ............................. 14ms DONE

With the above steps complete, your database is now set up and because the migrations were successful, you know your application is configured correctly to connect to the database.

Migrations

The above step invoked Laravel’s migration system. Migrations are files within your application that describe the structure of database tables your application uses. Having migrations is useful because it allows you to quickly set up your application’s database in different contexts (e.g. on a collaborator’s system, on a production server, etc.).

Migrations are found in the directory database/migrations. Exploring this directory you’ll see that Laravel comes with 4 default migrations. To learn how migrations work, let’s study the first default migration, 2014_10_12_000000_create_users_table.php:

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

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

Each migration contains an up method that describes changes that are to be made to the database, and a down method that would undo those changes.

Within the up method you can write code to create or alter database tables. This is done using the Schema class where you have access to many methods for constructing different column types in your table.

Create a migration

Let’s create migrations to set up some new tables for our application. We’ll start with a categories table, followed by a products table.

To create a new migration for a categories table run this command:

> php artisan make:migration create_categories_table

In the resulting file (/database/migrations/TIMESTAMP_create_categories_table.php), update your up method to look like this:

public function up(): void
{
    Schema::create('categories', function (Blueprint $table) {
        # Typically, every table has this id field which will act as a unique identifier for every row in the table
        $table->id(); 

        # The timestamps method adds two fields: created_at and updated_at. These fields are used to track when rows in the table are created and updated.
        $table->timestamps(); 

        # This will create a field called `name` that will expect string data. 
        # We will store the category name in this field
        $table->string('name'); 
    });
}

You can leave the down method as written:

public function down(): void
{
    Schema::dropIfExists('categories');
}

Next, create another migration for a products table:

> php artisan make:migration create_products_table

In the resulting file, update your up method to look like this:

public function up(): void
{
    Schema::create('products', function (Blueprint $table) {
        $table->id(); 
        $table->timestamps(); 

        # This field will store the product name
        $table->string('name'); 

        # Create a field called `category_id` to store the id of the category associated with a given product. Because this field will be a foreign key, we need to specify it’s unsigned.
        $table->bigInteger('category_id')->unsigned();

        # Specify that the category_id field is a foreign key that connects to the `id` field in the `categories` table
        $table->foreign('category_id')->references('id')->on('categories');
    });
}

You can leave the down method as written:

public function down(): void
{
    Schema::dropIfExists('products');
}

Running migrations

With your new migrations set up, run them with this command:

> php artisan migrate

Example output:

> php artisan migrate

   INFO  Running migrations.

  2023_09_13_200835_create_categories_table ............................. 13ms DONE
  2023_09_13_201447_create_products_table ............................... 19ms DONE

Behind the scenes, this is the resulting structure of our categories and products table: Resulting categories and products tables

Conclusion

In the next part of this guide, we’ll look at how we can write features in our application that will interact with the tables generated in the above steps.

If this info helped you out, toss a coin in the tip jar?
← Other topics