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
- 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 travelapicd 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...