January 5, 2024 · 5 min read · 245 views
We're excited to announce that we have updated all of our blog post examples to reflect the new Laravel 11 version! Our previous examples were based on Laravel 10, but with the release of Laravel 11, we wanted to ensure that our readers have access to the most up-to-date information and examples.
Setting up your database tables correctly is like laying the foundation for a building. For our Laravel app project, migrations are the blueprint that defines the structure of our data. Let's walk through the process of creating a robust database schema for a blog with users, profiles, posts, tags, and images using Laravel's migration system. Coding time!
Migrations in Laravel are PHP files that describe database changes, such as creating or altering tables. They give you the power to evolve your database schema over time in a version-controlled manner. Whether you're adding a new feature or modifying an existing one, migrations ensure that these changes are applied consistently across all environments.
Let's define the main features of our blog:
Users: The authors who write blog posts.
Profiles: The profiles of the users.
Posts: The articles or blog entries published by users.
Tags: Keywords or topics that categorize posts.
Images: Photos or graphics associated with posts or users.
Before we create the migrations, let's use the flag -mfsc
for creating everything that is needed: model, migration, controller, seeder and factory.
A new Laravel installation already has the User
model and seeder. That's why in this case we only need to create the seeder and the controller. Let's start with the seeder:
php artisan make:seeder UserSeeder
Now we create the controller with the command:
php artisan make:controller UserController
For the Profile
model, you might handle profile creation and updates through the UserController
. Thus, you wouldn't necessarily need a dedicated controller. We will need the model, migration, factory and seeder. We can create all of them through the command:
php artisan make:model Profile -mfs
For the Post
model, you typically want a controller to handle CRUD operations for blog posts. In this case, we need everything, that's why we added the -mfsc
flag. Let's create a model, a migration, a factory, a seeder and a controller through the command:
php artisan make:model Post -mfsc
For the Tag
model, you may not need a controller if tag management is done within another controller, like PostController
. That's why besides the model, we will create the migration, factory and seeder:
php artisan make:model Tag -mfs
Similarly, for the Image
model, if image uploads are managed through the PostController
, you may not need a separate controller:
php artisan make:model Image -mfs
Each command will create the following:
A model class in the app/Models
directory.
A migration file in the database/migrations
directory.
A factory file in the database/factories
directory.
A seeder file in the database/seeders
directory.
And for User
and Post
, where the -c
flag is included, it will also create:
A controller file in the app/Http/Controllers
directory.
Every blog needs authors, and in Laravel, we'll start by setting up a users
table. With the previous command, we already have a default migration file, and we will modify it to fit our blog application needs:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('email_verified_at')->nullable();
$table->string('password');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('users');
}
}
We also have a profiles
table that provides additional information about our users:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProfilesTable extends Migration
{
public function up()
{
Schema::create('profiles', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->text('bio')->nullable();
$table->string('website')->nullable();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('profiles');
}
}
The posts
table will hold all the blog entries written by our users:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePostsTable extends Migration
{
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('title');
$table->text('content');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('posts');
}
}
To help categorize posts, we'll set up a tags
table:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTagsTable extends Migration
{
public function up()
{
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->string('name')->unique();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('tags');
}
}
Since a post can have multiple tags and vice versa, we'll need a pivot table to establish a many-to-many relationship:php artisan make:migration create_post_tag_table --create=post_tag
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePostTagTable extends Migration
{
public function up()
{
Schema::create('post_tag', function (Blueprint $table) {
$table->foreignId('post_id')->constrained()->onDelete('cascade');
$table->foreignId('tag_id')->constrained()->onDelete('cascade');
$table->primary(['post_id', 'tag_id']); // Composite primary key
});
}
public function down()
{
Schema::dropIfExists('post_tag');
}
}
Lastly, we'll need a table to store images associated with our posts:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateImagesTable extends Migration
{
public function up()
{
Schema::create('images', function (Blueprint $table) {
$table->id();
$table->morphs('imageable');
$table->string('path'); // This will store the file path of the image
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('images');
}
}
Once these migration files are created, run them with Laravel's artisan command:
php artisan migrate
This command will execute each migration in order, creating your database schema as defined.
With these migrations, we've laid the groundwork for our blogging platform. Each table is designed to hold specific pieces of data, with relationships that reflect the real-world connections between users, their profiles, blog posts, tags, and images. Migrations provide a clear, version-controlled path to evolve this schema as our blog grows and changes, ensuring a solid foundation for our Laravel application.
This article is part of our series Laravel 11 for Beginners: A Step-by-Step Guide to Learn the Concepts.
If you need help with a Laravel project let's get in touch.
Lucky Media is proud to be recognized as a Top Laravel Development Agency
Technologies:
Related Posts
Stay up to date
Be updated with all news, products and tips we share!