Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here

DB Schema: Models, Migrations, Attributes

Premium
21:04

In this first lesson, we will create our DB structure with Migrations and Models. We have that structure from the client, so we must implement it. But it won't be that simple. There will be a few caveats along the way.

Plan of this lesson:

  • Create Models and Migrations
  • Solve the problem with word "Travel(s)" irregular plural form in Laravel
  • Create a Travel Model Accessor for the "number_of_nights" field
  • Create a Tour Model price() Attribute for float/integer conversion
  • Convert primary key integer IDs to UUIDs

The final result of this lesson will be this visual DB schema generated from a real database:

I'm a big fan of starting the project by building a DB schema because it gives a good feeling about the whole project scope, and raises important potential questions to the client that should be asked as early as possible cause, otherwise, they would lead to a lot of code changes later.


Initial DB Schema from Client

The client is quite technical but not with Laravel. So they provide us with the list of tables and columns, and our task is to convert it to Laravel Migrations/Models.

This is how the client described what we need to create.

Users

  • ID
  • Email
  • Password
  • Roles (M2M relationship)

Roles

  • ID
  • Name

Travels

  • ID
  • Is Public (bool)
  • Slug
  • Name
  • Description
  • Number of days
  • Number of nights (virtual, computed by numberOfDays - 1)

Tours

  • ID
  • Travel ID (M2O relationship)
  • Name
  • Starting date
  • Ending date
  • Price (integer, see below)

Also, here are a few points from the client's description that we need to keep in mind:

  • We use UUIDs as primary keys instead of incremental IDs;
  • Tours prices are integer multiplied by 100: for example, €999 euro will be 99900, but, when returned to Frontends, they will be formatted (99900 / 100).

With all that in mind, let's begin the creation process.

Obviously, we start with installing a new Laravel project, which I will call travelapi:

laravel new travelapi
cd travelapi

And now the database.


Role: Model and Migration

Laravel, by default, comes with a users DB table and Model, so we don't need to change anything there.

We need to create the table for roles and a pivot table between users and roles.

php artisan make:model Role -m

My personal preference is to create Eloquent Models with migrations right away. There are more options and classes to create, like Factories, Seeders, and more, but we will make them when we need them.

Migration file:

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

Notice: yes, I remember the client asked for UUIDs. We will refactor all keys to the UUIDs at the end of this lesson.

app/Models/Role.php:

class Role extends Model
{
use HasFactory;
 
protected $fillable = ['name'];
}

Notice about $fillable and Mass Assignment

Personally, I have a habit of filling in the $fillable array immediately when the migration is created. This is needed so we would be able to...

The Full Lesson is Only for Premium Members

Want to access all of our courses? (31 h 16 min)

You also get:

55 courses
Premium tutorials
Access to repositories
Private Discord
Get Premium for $129/year or $29/month

Already a member? Login here

Comments & Discussion

R
Ryan ✓ Link copied!

For role_user it may be helpful to have the user_id on delete cascade so when deleting a user it automatically deletes their roles.

PK
Povilas Korop ✓ Link copied!

Good suggestion, yes, agree.

RA
Richard A. Hoyle ✓ Link copied!

Grate course have been looking for something with these capabilities, Also can you give us some more on using DBeaver and what its capabilities are? Thanks

PK
Povilas Korop ✓ Link copied!

I don't use DBeaver for more than just exporting DB schema, so I can't tell more about it, please read its docs.

RC
Robinson Castro ✓ Link copied!

I have a question about database modeling. What if the business rules change over time? The previous modeling may no longer be suitable. For instance, relationships may change, and other aspects may become incorrect in the future. In such cases, how should we handle the data that has already been persisted in the database?

PK
Povilas Korop ✓ Link copied!
H
hrsa ✓ Link copied!

In case anyone struggles with the accessor: make sure that you are importing the correct Attribute class - the Laravel class and not the PHP standard one.

And if you imported the wrong one in the beginning, changed it, and it still won't work - php artisan optimize:clear.

GA
Gabriel Abiah ✓ Link copied!

Please I'm facing this error below after creating this in tinker App\Models\Travel::create(['name'=>'Some thing', 'description'=>'aaa', 'number_of_days'=>5]);

Error: Illuminate\Database\QueryException SQLSTATE[HY000]: General error: 1364 Field 'id' doesn't have a default value (Connection: mysql, SQL: insert into travels (name, description, number_of_days, slug, updated_at, created_at) values (Some thing, aaa, 5, s ome-thing, 2023-06-17 12:05:14, 2023-06-17 12:05:14)).

I have replaced the $table->id(); with $table->uuid('id')->primary(); in the travels migration file I have added HasUuids to my Travel model and also added use Illuminate\Database\Eloquent\Concerns\HasUuids;

H
hrsa ✓ Link copied!

Did you do php artisan migrate:fresh?

GA
Gabriel Abiah ✓ Link copied!

Yes I did. But I found the solution.

I was using the wampserver for my database before the issue popped up. So I decided to use MySQL workbench instead and there was no issue.

B
Babur ✓ Link copied!

When renaming create_travel_table to create_travels_table, don't forget to rename the dropping function as well in your migration as Schema::dropIfExists('travels');