Mohamed Allam
Laravel Example

Laravel Example

Laravel Migrations explained

Laravel Migrations explained

Laravel migrations explained, what is a migration? how to make one? what are columns types and much more.

Mohamed Allam's photo
Mohamed Allam

Published on Sep 18, 2021

11 min read

Subscribe to my newsletter and never miss my upcoming articles

Web developemment experience

A plethora of application development frameworks are available to programmers nowadays, as are thousands of components and libraries that are readily available to them. A common complaint among programmers is that by the time they master one framework, three newer (and presumably better) frameworks have arrived on the market, each claiming to be far better than the framework they are currently learning. all for free! how cool is that?

Thanks to open soure community.

Back in the early days of dynamic websites, developing a web application was considerably more difficult to accomplish than it is today. thus far less enjoyable experience for web developers.

Developers were thus in charge of building the code for not only the unique business logic of our applications, but also for each of the components that were blocks shared across various web applications and projects.

  • Routing
  • Requests
  • Templating
  • Controllers
  • Validation
  • Database access and more
  • and more

Laravel has been on the market for quite some time now, making the developers experience one of the most enjoyable ever. Interacting with Databases is no difference.

like Eloquent ActiveRecord ORM, object relational mapper. which will be our next topic.

But todays topic is migrations.

Usually to create a database table we would open up phpMyAdmin, Sequel Pro, or some other kind of sequel application and add each of these rows one at a time.

You might have encountered a situation in the past, such as instructing a coworker to manually add a column to their local database schema after bringing in your changes from source control. Or maybe you have decided to work from various computers.

Database migrations alleviate this kind of problems.

What are migrations?

When you use migrations, is essentially version control system for your database, allowing your team to define and share the definition of the application's database schema with each other.

A migration is a single file that defines your table. using command line. there is two things: the modifications desired when running php artisan migrate so migration up and, optionally, the modifications desired when running php artisan migrate:rollback the migration down. By the default they are located under database/migrations/folder

What does a Laravel migrations look like?

Laravel-migrations-folder.png

Laravel 8 comes with few migrations,

  1. 2014_10_12_000000_create_users_table.php
  2. 2014_10_12_100000_create_password_resets_table.php
  3. 2019_08_19_000000_create_failed_jobs_table.php
  4. 2019_12_14_000001_create_personal_access_tokens_table.php

Migration names explained

Timestamps

Each Migration file beings with the time and date it was created, The date provided gives Laravel which migration to run first. Or in other words creating tables needs you to give Laravel which Table has to be created first. or which columns. often table rows will be connected in relationships. so the source table has to be created first.

Each Post belong to an author, via author Id. so we need to create authors (users) table before the posts table. in order to reference in the posts table that author_id in posts table

Create or Add

Thae name of a migration has to be both understood for our application and for us. right. actually code we write has to be human readable as instructing machines isnt that hard. there for.

When we create a migration and it would create a table. we start with keyword create. and if its to add a column to an existing table we name it add.

PHP artisan make:migration

make-migration.png

To generate a migration file, we simply run php artisan make:migration —help

php artisan make:migration —help
Description:
  Create a new migration file

Usage:
  make:migration [options] [--] <name>

Arguments:
  name                   The name of the migration

Options:
      --create[=CREATE]  The table to be created
      --table[=TABLE]    The table to migrate
      --path[=PATH]      The location where the migration file should be created
      --realpath         Indicate any provided migration file paths are pre-resolved absolute paths
      --fullpath         Output the full path of the migration
  -h, --help             Display help for the given command. When no command is given display help for the list command
  -q, --quiet            Do not output any message
  -V, --version          Display this application version
      --ansi|--no-ansi   Force (or disable --no-ansi) ANSI output
  -n, --no-interaction   Do not ask any interactive question
      --env[=ENV]        The environment the command should run under
  -v|vv|vvv, --verbose   Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Arguments useful that we can pass to migration creation of a table

  • —create= this flag is useful when we explicitly want to give our migration a table name to create.
  • —create= this flag is useful when we explicitly want to give our migration table a name create or to define existing table name to add more columns via migration.
  • —path= to use a specific path location to our migration file, it can be useful in big scale projects where we have multiple migration folders.

Laravel migration to creating a new table in our database

When we open the Laravel default migration we see this code.

<?php

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

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        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.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

Migration codebase explained

CreateUsersTable.png

The class name will be exactly what this files does CreateUsersTable

This classes uses 3 main classes.

  • Migration abstract class to define connection and wether we want to wrap the migration in a transaction.
  • Schema Facade, that provide us with a fluent syntax code we can use to
    • Create and Drop a table create drop dropIfExists
    • Creata a Database createDatabase dropDatabaseIfExists
    • Toggle forigen key constraints disableForeignKeyConstraints enableForeignKeyConstraints
    • Check if columns exist hasColumn hasColumns
    • Get all columns names getColumnListing
    • Check if a table existshasTable
    • Create or Drops columns dropColumns
    • Table that takes Blueprint
  • Blueprint that instantiate $table to define columns names, types..etc which we will get in deep

Up and Down in Migrations

public function up()
{
  Schema::table('users', function (Blueprint $table) {
        // table definition goes here
        $table->string('name');
});

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

The table method on the Schema facade may be used to update existing tables. Like the create method, the table method accepts two arguments: the name of the table and a closure that receives an Illuminate\Database\Schema\Blueprint instance you may use to add columns to the table.

  • Up method is the function that takes Schema Facade defines the table name, and Blueprint in a closue, to define the colmns names types and other configuration or parameters you normally would do manually in a SQL client interface.
  • Down method is to roll back or drop what the up does

Migration files that creates an actual table, the down method should be the table name

Migration files that adds columns to an exisiting table, down method would only be this columns names

Laravel Migration for Adding columns to an existing table

Many times we create a table, later on we realize we want to add a column to it, and of course, we want to make sure that rolling back would only take down this columns changes and not the entire database

php artisan make:migration add_two_factor_authentication_to_users_table

As readable as it is, It adds a column to table, Laravel magic will autoatically

<?php

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

class AddTwoFactorAuthenticationToUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
                        // line of code to create the column
                        $table->string('code');

        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
                        // line of code to roll back!
            $table->dropIfExists('code');
        });
    }
}

Running Migrations command and helpers

php artisan migrate

This command runs all “outstanding” migrations (so it does run the up() method on each). However Laravel keeps track of which migrations you have run and which you haven’t. Every time you run this command, it checks whether you’ve run all available migrations, and if you haven’t, it’ll run any migrations that remain.

php artisan make:migration create_products_table

Creates a migration file, with CreateProductsTable class, where we can define the schema of this table.

php artisan migrate:install

Creates the database table that keeps track of which migrations you have and haven’t run; this is run automatically when you run your migrations, so you can basically ignore it.

php artisan migrate:reset

Rolls back every database migration you’ve run on this instance.

php artisan migrate:refresh

Rolls back every database migration you’ve run on this instance, and then runs every migration available. It’s the same as running migrate:reset and then migrate, one after the other.

php artisan migrate:fresh

Drops all of your tables and runs every migration again. It’s the same as refresh but doesn’t bother with the “down” migrations—it just deletes the tables and then runs the “up” migrations again.

php artisan migrate:rollback
//or 
php artisan migrate:rollback() --steps=3

Rolls back just the migrations that ran the last time you ran migrate, or, with the added option --step=n, rolls back the number of migrations you specify.

php artisan migrate:status

Shows a table listing every migration, with a Y or N next to each showing whether or not it has run yet in this environment.

Migrations columns types

Laravel documentation has all available columns types

Laravel-available-columns-types.png

We can have most SQL types fluently: to name few

  • integer
  • boolean
  • binary
  • string
  • char
  • datetime
  • json
  • uuid
public function up()
    {
        Schema::table('users', function (Blueprint $table) {

                    //Adds an INTEGER type column, or one of its many variations
                    $table->integer('some_column_name');
                    $table->tinyInteger('some_column_name');
                    $table->smallInteger('some_column_name');
                    $table->mediumInteger('some_column_name');
                    $table->bigInteger('some_column_name');

                    //Adds an unsigned INTEGER type column, or one of its many variations
                    $table->unsignedBigInteger('some_column_name');
                    $table->unsignedInteger('some_column_name');
                    $table->unsignedMediumInteger('some_column_name');
                    $table->unsignedSmallInteger('some_column_name');
                    $table->unsignedTinyInteger('some_column_name');

                    // Adds a VARCHAR type column with an optional length
                    $table->integer('some_column_name', 'length');

                    // Adds a BLOB type column
                    $table->binary('some_column_name');

                    // Adds a BOOLEAN type column (a TINYINT(1) in MySQL)
                    $table->boolean('some_column_name');

                    // Adds a CHAR column with an optional length
                    $table->char('some_column_name', 'length');

                    // Adds a DATETIME column
                    $table->datetime('some_column_name');

                    // Adds a DECIMAL column, with precision and scale—for example, decimal('amount', 5, 2) specifies a precision of 5 and a scale of 2
                    $table->decimal('some_column_name', 'precision', 'scale');

                    // unsigned decimal
                    $table->unsignedDecimal('some_column_name');

                    // Adds a DOUBLE column—for example, double('tolerance', 12, 8) specifies 12 digits long, with 8 of those digits to the right of the decimal place, as in 7204.05691739
                    $table->decimaldouble('some_column_name', 'total_digits', 'digits_after_decimal');

                    //unsigned double
                    $table->unsignedDouble('some_column_name');

                    // Adds an ENUM column, with provided choices
                    $table->enum('some_column_name', ['choiceOne', 'choiceTwo']);

                    //Adds a FLOAT column (same as double in MySQL
                    $table->float('some_column_name', 'precision', 'scale');

                    // Adds unsinged float column
                    $table->unsignedFloat('some_column_name');

                    //Adds a JSON or JSONB column (or a TEXT column in Laravel 5.1)
                    $table->json('some_column_name');
                    $table->jsonb('some_column_name');

                    //Adds a TEXT column (or its various sizes)
                    $table->text('some_column_name');
                    $table->mediumText('some_column_name');
                    $table->longText('some_column_name');
                    $table->tinyText('some_column_name');

                    //Adds a TIME column
                    $table->time('some_column_name');

                    //Adds a TIMESTAMP column
                    $table->timestamp('some_column_name');

                    //Adds a UUID column (CHAR(36) in MySQL)
                    $table->uuid('some_column_name');

                    //“And these are the special (joined) Blueprint methods:

                    //“Add an unsigned incrementing INTEGER or BIG INTEGER primary key ID or one of its variations
                    $table->increments('some_column_name');
                    $table->bigIncrements('some_column_name');
                    $table->tinyIncrements('some_column_name');
                    $table->smallIncrements('some_column_name');
                    $table->mediumIncrements('some_column_name');

                    // Adds created_at and updated_at timestamp columns
                    $table->timestamps();
                    $table->nullableTimestamps();

                    //Adds a remember_token column (VARCHAR(100)) for user “remember me” tokens
                    $table->rememberToken();

                    // Adds a deleted_at timestamp for use with soft deletes
                    $table->softDeletes();

                    // Adds an integer some_column_name_id and a string some_column_name_type (e.g.,
                    //morphs(tag) adds integer tag_id and string tag_type); for use in polymorphic relationships
                    $table->morphs('some_column_name');


    });
}

Column Modifiers

Many times you need modifiers, like when you want a table to be nullable, you would with →nullable() ,

// modifiers
//Place the column "first" in the table (MySQL).
$table->string('some_column_name')->first();

//Place the column "after" another column (MySQL).
$table->string('some_column_name')->after('another_column_name');

//Allow NULL values to be inserted into the column.
$table->string('some_column_name')->nullable();

//Allow NULL values to be inserted into the column. or a default value
$table->string('some_column_name')->nullable('some default value');

//Specify a "default" value for the column.
$table->string('some_column_name')->default('default');

// Set INTEGER columns as auto-incrementing (primary key).
$table->integer('some_column_name')->autoIncrement();

//Set the starting value of an auto-incrementing field (MySQL / PostgreSQL).
$table->integer('some_column_name')->from('some interger');

//Set INTEGER columns as UNSIGNED (MySQL).
$table->integer('some_column_name')->unsigned();

//Specify a character set for the column (MySQL).
$table->charset('utf8mb4');

//Specify a collation for the column (MySQL/PostgreSQL/SQL Server).
$table->string('some_column_name')->collation('utf8mb4_unicode_ci');

//Add a comment to a column (MySQL/PostgreSQL).
$table->comment('my comment');

//Set TIMESTAMP columns to use CURRENT_TIMESTAMP as default value.
$table->timestamp('some_column_name')->useCurrent();

//Set TIMESTAMP columns to use CURRENT_TIMESTAMP when a record is updated.
$table->timestamp('some_column_name')->useCurrentOnUpdate();

//Create a virtual generated column (MySQL).
$table->string('some_column_name')->virtual('$expression');

//Create an identity column with specified sequence options (PostgreSQL).
$table->string('some_column_name')->generatedAs('$expression');

Renaming column names

To rename a column, you may use the renameColumn method provided by the schema builder blueprint. Before renaming a column, ensure that you have installed the doctrine/dbal library via the Composer package manager:

Schema::table('users', function (Blueprint $table) {
    $table->renameColumn('from', 'to');
});

Foregin key constraints

Laravel also provides support for creating foreign key constraints, which are used to force referential integrity at the database level. For example, let's define a user_id column on the posts table that references the id column on a users table.

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

Schema::table('posts', function (Blueprint $table) {
    $table->unsignedBigInteger('user_id');

    $table->foreign('user_id')->references('id')->on('users');
});

Laravel now provides even less verbose syntax to define foreign key constrainsts

Schema::table('posts', function (Blueprint $table) {
    $table->foreignId('user_id')->constrained();
});

This will make Laravel magic, finds the Id of the user, in the Users table, as its the convenience way, however if for yoru cases you want to specifc which table.

You pass it in the constrained method

Schema::table('posts', function (Blueprint $table) {
    $table->foreignId('user_id')->constrained('users');
});

To specicfy what kind of actions we want to accomplish we can do that onUpdate and onDelete

$table->foreignId('user_id')
      ->constrained()
      ->onUpdate('cascade')
      ->onDelete('cascade');

If we do have anything additional modifiers we should pass that before constrained method.

$table->foreignId('user_id')
      ->nullable()
      ->constrained();

Events

Laravel provides some events to dispatch whenever a migration runs.

Illuminate\Database\Events\MigrationsStarted
Illuminate\Database\Events\MigrationsEnded
Illuminate\Database\Events\MigrationStarted
Illuminate\Database\Events\MigrationEnded

Migrations allow us to save and version our database schema in our project files! What about the actual data that gets inserted into our database? What if we had some data that we wanted to seed into our database schema. Simple enough we can do that by using Seeds. Let’s learn more about these in the follow up article chapter.

 
Share this
Proudly part of