Creating Your First Blog With TALL - Part Three

By Alhassan Kamil on Mar 11, 2021
TALL image part 3

Hello and welcome to the third episode of the Creating Your First Blog With TALL tutorial series. You learnt how to configure Jetstream, setup database connection, create routes, create a symlink and change the default Jetstream logo in the previous episode.

In this episode, you’re going to learn how to setup and run migrations to create the tables for our blog and create the needed models for the project. At the end, you should be able to:

  1. Get a basic understanding of the alternative ways Laravel lets you run database queries.
  2. Know and explain what Laravel Eloquent models and migrations are.
  3. Create models and migrations for any Laravel project
  4. Run migrations for our project

Okay. Take a sip of coffee and let’s dive in right away. :)

The Alternative Ways Database Queries are Run in Laravel

If you’re coming from the traditional way of developing web apps using plain PHP, you may be blown away by how much Laravel eases the pain of handling database operations. Think about having to manually write SQL queries, take care of SQL vulnerabilities like SQL injection, and many others that you’ll have to deal with, all taken care of by the framework.

In Laravel, you not only have to not manually write SQL commands in your PHP code, you have several options on how you want to run your database queries, including what you’re used to when developing using plain PHP (albeit in a very simplified, easier way). You can write Laravel database operations using either raw SQL, the Laravel Query Builder or Eloquent models. We’ll only look at the latter two in this tutorial. You can learn more about running raw SQL queries here.

Using Query Builder to Run Database Queries

The Query Builder is a general and convenient way of creating and running database queries. It can be used to run most of the database query operations supported by your database driver through the DB facade. The DB facade provides a convenient table method you can use to run queries against a given table. Other methods of the DB facade such as insert, update, select, where, delete, get etc can then be chained to the table method to run those respective queries like so:

use Illuminate\Support\Facades\DB;

// Select all users
$users = DB::table('users')->get();

// Select only approved users
$users = DB::table('users')->where('approved', true)->get();

// Delete all users
DB::table('users')->delete();

// Insert a new user
DB::table('users')->insert([
    'username' => 'awesomeuser',
    'email' => 'awesomeuser@example.com'
]);

// Update an existing user
$userAffected = DB::table('users')
              ->where('id', 2)
              ->update(['username' => 'mynewawesomename']);

Using Eloquent to Run Database Queries

Laravel Eloquent is an Object-Relational Mapper (ORM) that enables you to run database queries using models. Models allow you to store data and handles the logic that goes with it. With Eloquent, each table has a corresponding model class that deals with querying and storing data in that table. Since the rest of this tutorial will entirely be on using Eloquent, I’ll leave explanation of Eloquent models here and continue with the other sections.

Creating Eloquent Models and Migrations

Eloquent Models

As I pointed out above, Eloquent models help you to store data and its related logic. Models act like data warehouse operators - any data entering/leaving the warehouse goes through them, they keep track of and update records, they can filter and sort items out, they know how to sanitize and check data for integrity and so much more.

Database Migrations

The Laravel docs does so well in explaining what migrations are and I won’t repeat myself here. This is what the docs say about migrations:

Migrations are like version control for your database, allowing your team to define and share the application’s database schema definition. If you have ever had to tell a teammate to manually add a column to their local database schema after pulling in your changes from source control, you’ve faced the problem that database migrations solve.

How to Create Eloquent Models

Like many other Laravel features, you can create Eloquent models by running Artisan commands from the terminal. To create a model, use the make:model command like so:

php artisan make:model ModelName

Where ModelName is the actual name of the model you want to create. This creates the given model (which extends \Illuminate\Database\Eloquent\Model) in the app\Models directory. You can optionally pass -m, -c, -f, -s to respectively create a migration, controller, factory or a database seeder(we’ll explain these later in the coming series) in addition to the given model, or even combine these options, like so:

php artisan make:model ModelName -m // creates migration too
php artisan make:model ModelName -c // creates controller too
php artisan make:model ModelName -f // also creates a factory
php artisan make:model ModelName -s // also creates a database seeder
php artisan make:model ModelName -mfcs // creates migration, factory, controller and seeder

How to Create Migrations

Migrations are created by running the make:migration Artisan command, passing the name of the migration and an optional --path argument to specify where the migration should be placed. So creating a migration for ModelName above will look like below:

php artisan make:migration create_model_names_table

This will create a create_model_names_table migration in the database/migrations directory with two methods: up and down. up is used to add tables, indices and columns while down reverses these actions. For an in-depth understanding of migrations and models, please consult the official docs.

Creating Models and Migrations for Our Blog

Now that you have learnt what models and migrations are and how to create them, lets move on to create the models and migrations our blog will need. Because this is an introductory tutorial, our blog will only have one Post model in addition to the built-in User model (in a real world blog you’ll definitely want to add other models such as category and tag models, but we don’t wanna make this tutorial complicated and so we’ll keep things as simple as possible.). And because there is a relationship between a blog post and the user who wrote it, we’ll have to establish a database relationship here.

In any blogging system, a blog post belongs to a particular user. A user can have as many blog posts as they choose to. In this case of ours, a blog post cannot belong to multiple users, so we have a one-to-many relationship between users and posts. Laravel supports different kinds of entity relationships and one-to-many is just one of them we’ll use in this tutorial.

To define the relationship a user has on posts, open the app/Models/User.php file and add this method to the end of it:

// tall-blog/app/Models/User.php
...
...
...
/**
* Get the posts for this user
*/
public function posts() {
    return $this->hasMany(Post::class);
}
...

This creates a one-to-many relationship to the Post model and allows us to get a user’s posts by calling $user->posts on an existing $user object. If you see errors that the Post class doesn’t exist just ignore it since that’s what we’re going to create next.

Create the Post model by running the make:model command and by specifying the -m, -s, and -f options:

php artisan make:model Post -mfs

This will create the Post model in app/Models. In addition, a new migration will be created in the database/migrations directory, a new model factory in database/factories and a database seeder in database/seeders.

Open the app/Models/Post.php model file and make sure its contents is exactly as follows:

// tall-blog/app/Models/Post.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model {
    use HasFactory;

    /**
     * Columns that are mass assignable
     */
    protected $fillable = [
        'title', 'excerpt', 'body', 'category',
        'featured_image', 'published_date',
        'is_published', 'user_id'
    ];

    /**
     * Returns the user for this post
     */
    public function user() {
        return $this->belongsTo(User::class)->withDefault();
    }
}

First of all, we’re importing the HasFactory facade and the base Model class. Using the HasFactory facade here means the Post class has access to the factory method of the HasFactory facade, which is used to create factories. Our Post class extends the base Model class, which every model extends and therefore, will inherit all the methods available in the Model class. We have also defined the $fillable array property of the base Model class, which lists the attributes of the Post model that are mass assignable. Remember these attributes are also the columns for our posts table.

Lastly, we have defined a reverse one-to-many relationship between a post and its owner - a user. Just like the one-to-many relationship we defined for the User model, adding the reverse relationship this way enables us to query an existing Post object’s user by simply calling $post->user.


We already learnt how to create migrations and we have even created the create_posts_table migration above when we run the make:model with the -m option specified. As I mentioned already, this migration is located in the database/migrations directory. Open it(Laravel prepends the current date to a migration’s name when you create it, so you’d have to consider that when you’re looking for the migration) and ensure the up method looks exactly as below:

// tall-blog/database/migrations/2021_03_10_141045_create_posts_table.php 
/**
 * Run the migrations.
 *
 * @return void
*/
public function up() {
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('category');
        $table->string('excerpt');
        $table->longText('body');
        $table->string('title');
        $table->boolean('is_published')->default(false);
        $table->string('featured_image');
        $table->dateTime('published_date');
        $table->foreignId('user_id')->constrained();
        $table->timestamps();
    });
}

All we’re doing here is creating the ’posts’ table using the create method from the Schema facade. This method accepts the table to create as the first argument and a closure that uses the given Blueprint to define columns for the table. Ignoring all the column types (which you can learn here), we’re also specifying an auto-incrementing ID column(from $table->id()) for our table, a foreign ID constraint that references the ‘users’ table at the database level(from $table->foreignId('user_id')->constrained()), and a timestamps columns (from $table->timestamps()) that will automatically create a created_at and updated_at columns for us.

Save the file. Ensure your database server is running and run the migrations to create the posts table:

php artisan migrate

If everything went well, you should get an output such as this:

kamil@kamil-sc650:~/Projects/Web/tall-blog$ php artisan migrate
Migrating: 2020_05_21_100000_create_teams_table
Migrated: 2020_05_21_100000_create_teams_table (3,058.26ms)
Migrating: 2020_05_21_200000_create_team_user_table
Migrated: 2020_05_21_200000_create_team_user_table (1,294.05ms)
Migrating: 2020_05_21_300000_create_team_invitations_table
Migrated: 2020_05_21_300000_create_team_invitations_table (3,464.26ms)
Migrating: 2021_03_10_141045_create_posts_table
Migrated: 2021_03_10_141045_create_posts_table (3,663.84ms)

You can check to see the created tables in the tall_blog database by using the terminal client for your database server or a GUI program such as phpMyAdmin, if you’re using MySQL.

This brings us to the end of this episode of the Creating Your First Blog With TALL tutorial series and I hope you enjoyed the tutorial. In the next episode, you’ll learn how to create model factories and database seeders in order to fill our database with sample data.

See you for the next post.

Subscribe to my Newsletter

Never miss out on new tips, tutorials, and more on tech. Subscribe to my newsletter for awesome content. No spam!