Mastering Models in Laravel
Laravel — P36: Seeders and Factories (CMP)
Fillable
In order to add data inside of our tables when we submit our forms, we need to specify which fields are fillable. We could “cheat,” and quite a few developers do, by eliminating this check. To do that, you set the $guarded
variable to an empty array. We won’t do that. We’ll specify which fields can be inserted.
PersonalCar
The PersonalCar
contains all of the fields except a couple:
id
personal_car_brand_id
personal_car_model_id
created_at
updated_at
The id
, created_at
, and updated_at
fields are generated automatically through mysql. The foreign id’s will be inserted via relationships, so we don’t need to add those to the $fillable
property.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class PersonalCar extends Model
{
use HasFactory;
protected $fillable = [
'year', 'is_manual', 'exterior_color', 'purchase_amount', 'current_value', 'sales_amount', 'date_purchased', 'date_sold'
];
}
PersonalCarBrand
Similarly, we add the fillable fields for the PersonalCarBrand
.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class PersonalCarBrand extends Model
{
use HasFactory;
protected $fillable = [
'name', 'slug',
];
}
PersonalCarModel
We’ll repeat the process for PersonalCarModel
.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class PersonalCarModel extends Model
{
use HasFactory;
protected $fillable = [
'name', 'slug',
];
}
Image
Remember the Image
model? I know that we haven’t looked at it until now, but our cars will have images. We need to make sure those fields are fillable as well.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Image extends Model
{
use HasFactory;
protected $fillable = [
'url', 'alt',
];
}
Do we need to do anything for our image_personal_car
pivot table? Not yet. That’ll be tackled when we look at relationships.
Relationships
We haven’t looked at any sort of relationships yet. I wanted to throw in a couple of relationships into the mix, but we’ll take a deep dive into relationships later. For now, let’s create our first relationship. Let’s tackle the personal_car_brand_id
in our PersonalCar
model.
BelongsTo
If we think about it, our PersonalCarBrand
can have many PersonalCars
. Our PersonalCar
can’t have many PersonalCarBrands
. Remember, we’re talking about one instance of the model. If I look at one of my cars, a 2007 Chevy Corvette, it belongs to one specific brand: Chevy. However, if I look at Chevy, I can see that the brand has two cars that are associated with it, since I have a 2003 Chevy Corvette as well (kind of obsessed with those cars). So Chevy hasMany
cars associated with it, but my 2007 Chevy Corvette belongsTo
one brand.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class PersonalCar extends Model
{
use HasFactory;
protected $fillable = [
'year', 'is_manual', 'exterior_color', 'purchase_amount', 'current_value', 'sales_amount', 'date_purchased', 'date_sold'
];
public function brand()
{
return $this->belongsTo(PersonalCarBrand::class, 'personal_car_brand_id', 'id');
}
}
We created a brand
method. It returns a belongsTo
relationship. It’s saying that the PersonalCar
belongsTo
a PersonalCarBrand
. The second argument is the foreign key inside of our PersonalCar
and the third argument is the key that we’re referencing in our PersonalCarBrand
, in this case it’s id
.
Let’s test and see if it works. Open tinker
.
# php artisan tinker;
Psy Shell v0.11.9 (PHP 8.1.13 — cli) by Justin Hileman
> PersonalCar::first();
= App\Models\PersonalCar {#4722
id: 1,
year: "2022",
personal_car_brand_id: 6,
personal_car_model_id: 6,
is_manual: 1,
exterior_color: "itaque",
purchase_amount: 21846038,
current_value: 635120796,
sales_amount: 0,
date_purchased: "2014-01-18",
date_sold: null,
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
}
>
tinker
, we can assign the model to a variable, like $car
.> $car = PersonalCar::first();
= App\Models\PersonalCar {#4504
id: 1,
year: "2022",
personal_car_brand_id: 6,
personal_car_model_id: 6,
is_manual: 1,
exterior_color: "itaque",
purchase_amount: 21846038,
current_value: 635120796,
sales_amount: 0,
date_purchased: "2014-01-18",
date_sold: null,
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
}
>
> $car->brand();
= Illuminate\Database\Eloquent\Relations\BelongsTo {#4724}
>
first()
or get()
.> $car->brand()->first();
= App\Models\PersonalCarBrand {#4727
id: 6,
name: "Quidem",
slug: "quidem",
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
}
>
->get()
or ->first()
each time and that’s to just get rid of the parentheses. You’ll see this type of syntax most often.> $car->brand;
= App\Models\PersonalCarBrand {#4728
id: 6,
name: "Quidem",
slug: "quidem",
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
}
>
Now, if we wanted to look at the name of our car, we could simply go directly to the name
property of our PersonalCarBrand
model.
> $car->brand->name;
= "Quidem"
>
with()
method and specifying the relationship that you want to eager load.> $car = PersonalCar::with('brand')->first();
= App\Models\PersonalCar {#4718
id: 1,
year: "2022",
personal_car_brand_id: 6,
personal_car_model_id: 6,
is_manual: 1,
exterior_color: "itaque",
purchase_amount: 21846038,
current_value: 635120796,
sales_amount: 0,
date_purchased: "2014-01-18",
date_sold: null,
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
brand: App\Models\PersonalCarBrand {#4738
id: 6,
name: "Quidem",
slug: "quidem",
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
},
}
>
As you can see, our brand
is already loaded.
Let’s repeat the process for our PersonalCarModel
relationship.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class PersonalCar extends Model
{
use HasFactory;
protected $fillable = [
'year', 'is_manual', 'exterior_color', 'purchase_amount', 'current_value', 'sales_amount', 'date_purchased', 'date_sold'
];
public function brand()
{
return $this->belongsTo(PersonalCarBrand::class, 'personal_car_brand_id', 'id');
}
public function model()
{
return $this->belongsTo(PersonalCarModel::class, 'personal_car_model_id', 'id');
}
}
tinker
or it won’t work properly (CTRL+C
).> $car = PersonalCar::with(['brand', 'model'])->first();
[!] Aliasing 'PersonalCar' to 'App\Models\PersonalCar' for this Tinker session.
= App\Models\PersonalCar {#4721
id: 1,
year: "2022",
personal_car_brand_id: 6,
personal_car_model_id: 6,
is_manual: 1,
exterior_color: "itaque",
purchase_amount: 21846038,
current_value: 635120796,
sales_amount: 0,
date_purchased: "2014-01-18",
date_sold: null,
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
brand: App\Models\PersonalCarBrand {#4727
id: 6,
name: "Quidem",
slug: "quidem",
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
},
model: App\Models\PersonalCarModel {#4731
id: 6,
name: "Vel",
slug: "vel",
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
},
}
>
The with()
method can accept a string if it’s just one relationship, or an array if there are multiple relationships that you’re trying to eager load.
$car = PersonalCar::with(['brand', 'model'])->first();
As you can see, we have all of our PersonalCar
properties and both of our relationships loaded.
hasMany
What if we wanted to see all of the cars that are associated with our brands and models? We’ll need to setup hasMany
relationships on those.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class PersonalCarBrand extends Model
{
use HasFactory;
protected $fillable = [
'name', 'slug',
];
public function cars()
{
return $this->hasMany(PersonalCar::class, 'personal_car_brand_id', 'id');
}
}
The cars
method states that the PersonalCarBrand
hasMany
cars. Those cars are stored in the PersonalCar
model and the foreign id that links back to our PersonalCarBrand
from PersonalCar
is the personal_car_brand_id
. It’s linked to the id
on PersonalCarBrand
.
> $brand = PersonalCarBrand::with(['cars'])->find(6);
[!] Aliasing 'PersonalCarBrand' to 'App\Models\PersonalCarBrand' for this Tinker session.
= App\Models\PersonalCarBrand {#4717
id: 6,
name: "Quidem",
slug: "quidem",
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
cars: Illuminate\Database\Eloquent\Collection {#4720
all: [
App\Models\PersonalCar {#4725
id: 1,
year: "2022",
personal_car_brand_id: 6,
personal_car_model_id: 6,
is_manual: 1,
exterior_color: "itaque",
purchase_amount: 21846038,
current_value: 635120796,
sales_amount: 0,
date_purchased: "2014-01-18",
date_sold: null,
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
},
],
},
}
When we eager load our relationship, we see that the cars
key contains an array of cars. In this instance, there’s only one car associated with this particular object (row 6). If we try another one, we can see that sometimes we get no results and other times we get multiple results.
> $brand = PersonalCarBrand::with(['cars'])->find(1);
= App\Models\PersonalCarBrand {#4726
id: 1,
name: "Dolorem",
slug: "dolorem",
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
cars: Illuminate\Database\Eloquent\Collection {#4730
all: [],
},
}
>
> $brand = PersonalCarBrand::with(['cars'])->find(7);
= App\Models\PersonalCarBrand {#4751
id: 7,
name: "Quam",
slug: "quam",
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
cars: Illuminate\Database\Eloquent\Collection {#4771
all: [
App\Models\PersonalCar {#4779
id: 5,
year: "1991",
personal_car_brand_id: 7,
personal_car_model_id: 10,
is_manual: 0,
exterior_color: "tempora",
purchase_amount: 28457362,
current_value: 720832497,
sales_amount: 0,
date_purchased: "1984-05-10",
date_sold: null,
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
},
App\Models\PersonalCar {#4777
id: 8,
year: "1974",
personal_car_brand_id: 7,
personal_car_model_id: 4,
is_manual: 1,
exterior_color: "tenetur",
purchase_amount: 2236172,
current_value: 779288418,
sales_amount: 0,
date_purchased: "1979-07-15",
date_sold: null,
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
},
],
},
}
>
PersonalCarModel
if we find the need for it. I think it’s good practice to do it, so let’s do it.<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class PersonalCarModel extends Model
{
use HasFactory;
protected $fillable = [
'name', 'slug',
];
public function cars()
{
return $this->hasMany(PersonalCar::class, 'personal_car_brand_id', 'id');
}
}
It’s exactly the same code that we used in our PersonalCarBrand
. We can now eager load it and check to see the results.
> PersonalCarModel::with('cars')->find(3);
= App\Models\PersonalCarModel {#4735
id: 3,
name: "Consequuntur",
slug: "consequuntur",
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
cars: Illuminate\Database\Eloquent\Collection {#4738
all: [
App\Models\PersonalCar {#4744
id: 4,
year: "2018",
personal_car_brand_id: 3,
personal_car_model_id: 1,
is_manual: 0,
exterior_color: "mollitia",
purchase_amount: 47028382,
current_value: 285870699,
sales_amount: 0,
date_purchased: "1985-05-25",
date_sold: null,
created_at: "2023-01-20 20:37:11",
updated_at: "2023-01-20 20:37:11",
},
],
},
}
>
For image, there’s a little more to it, so we’ll tackle that one in the next article since I want to make sure that you understand the pivot table concept thoroughly. I think we covered enough here. See you next time.
Laravel Series
Continue your Laravel Learning.
Master Data Generation with Laravel Seeders and Factories
Laravel – P36: CMP – Seeders/Factories
Learn how to efficiently use Laravel seeders and factories for data generation in your projects. Boost productivity and streamline your workflow.
Mastering Models in Laravel: $fillable, belongsTo, and hasMany
Laravel – P37: CMP – Models $Fillable, Belongsto and Hasmany
Explore Laravel models with a focus on $fillable, belongsTo, and hasMany. Understand how to efficiently manage relationships and data handling in your projects.
Laravel Relationships Unlocked: Using belongsToMany, attach, and detach
Laravel – P38: CMP – Many To Many Relationship belongsToMany, attach, detach
Learn how to manage many-to-many relationships in Laravel using belongsToMany, attach, and detach. Simplify complex data links in your applications.