Laravel Models 101: A Beginner's Guide
Table of contents
- 1. What is a Laravel Model?
- 2. Creating Models in Laravel
- 3. Basic Model Properties
- 4. Eloquent ORM: Querying and Manipulating Data
- 5. Defining Relationships in Models
- 6. Mass Assignment and Fillable Properties
- 7. Model Events and Observers
- Understanding the #[ObservedBy] Attribute
- Example of Using the ObservedBy Attribute
- No Need to Register in AppServiceProvider
- Benefits of the #[ObservedBy] Attribute
- Example Scenario
- 8. Eloquent Accessors and Mutators
- 9. Timestamps and Soft Deletes
- 10. Conclusion
Laravel models are the backbone of its robust MVC (Model-View-Controller) framework. They represent the data layer in your application, encapsulating the logic for interacting with the database. In this guide, we will walk through the basics of Laravel models, focusing on how to use them effectively, from defining models and relationships to using Eloquent, Laravel's powerful ORM (Object-Relational Mapping).
1. What is a Laravel Model?
In Laravel, a model is a class that represents a table in your database. It allows you to interact with data, define relationships between different tables, and perform CRUD (Create, Read, Update, Delete) operations without writing complex SQL queries.
At the core, models in Laravel use Eloquent, Laravel's built-in ORM, which provides an expressive syntax to interact with databases.
2. Creating Models in Laravel
Laravel offers an Artisan command to quickly generate models. To create a model, use the following command:
php artisan make:model Product
This will generate a model file in the app/Models
directory:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
// Your model logic here
}
With Migration:
You can also create a model with a corresponding migration using the -m
flag:
php artisan make:model Product -m
This will create both the model and a migration file where you can define your database schema.
3. Basic Model Properties
Laravel models come with some default properties and behaviors. Here are a few key properties you should know:
$table: This property specifies the database table that the model is associated with. By default, Laravel assumes the table name is the plural form of the model name. If you want to specify a different table, you can override this:
protected $table = 'products';
$primaryKey: By default, Laravel assumes the primary key column is named
id
. If your primary key has a different name, you can specify it:protected $primaryKey = 'product_id';
$timestamps: Laravel automatically maintains
created_at
andupdated_at
fields for models. If you don't want this behavior, set the$timestamps
property tofalse
:public $timestamps = false;
$connection: If your model needs to connect to a different database than the default one, you can specify the connection:
protected $connection = 'mysql2';
4. Eloquent ORM: Querying and Manipulating Data
Laravel's Eloquent ORM allows you to interact with the database using simple and expressive syntax. Here are some common operations:
Retrieving Data
Retrieve all records:
$products = Product::all();
Find a record by primary key:
$product = Product::find(1);
Retrieve the first record that matches a condition:
$product = Product::where('name', 'Laptop')->first();
Inserting Data
To create a new record in the database, you can either use the create
method or manually assign values and save:
$product = new Product();
$product->name = 'Laptop';
$product->price = 999.99;
$product->save();
Alternatively, using the create
method with mass assignment:
Product::create([
'name' => 'Laptop',
'price' => 999.99,
]);
(Note: Be sure to define the $fillable
property for mass assignment, as explained later.)
Updating Data
To update a model:
$product = Product::find(1);
$product->price = 899.99;
$product->save();
Deleting Data
To delete a model:
$product = Product::find(1);
$product->delete();
Or, delete by a condition:
Product::where('price', '>', 1000)->delete();
5. Defining Relationships in Models
Eloquent makes defining relationships between different models easy. Relationships are crucial when you have data that connects tables (e.g., users and posts).
Here are the types of relationships you can define in your models:
One-to-One
A one-to-one relationship means that one model is related to exactly one other model:
class User extends Model
{
public function profile()
{
return $this->hasOne(Profile::class);
}
}
One-to-Many
A one-to-many relationship means that one model can have multiple related models:
class Post extends Model
{
public function comments()
{
return $this->hasMany(Comment::class);
}
}
Many-to-Many
A many-to-many relationship means that one model can belong to many other models and vice versa:
class User extends Model
{
public function roles()
{
return $this->belongsToMany(Role::class);
}
}
6. Mass Assignment and Fillable Properties
Mass assignment allows you to easily insert multiple values into a model. However, for security purposes, Laravel requires you to define the $fillable
property to specify which fields can be mass assigned.
class Product extends Model
{
protected $fillable = ['name', 'price'];
}
If you don’t specify $fillable
, Laravel will throw a MassAssignmentException
when trying to mass assign attributes.
7. Model Events and Observers
In Laravel 10+, a new way to register model observers was introduced through the #[ObservedBy]
attribute. This feature simplifies how we attach observers to Eloquent models, eliminating the need to manually register observers within a service provider like AppServiceProvider
. Instead, you can directly link an observer class to a model using the ObservedBy
attribute on the model itself.
Understanding the #[ObservedBy]
Attribute
The #[ObservedBy]
attribute is a PHP 8+ attribute that you can attach to a model class. It makes the connection between a model and its observer explicit and more readable. Laravel automatically detects and registers the observer when the application is booted, without needing to manually declare it in the service provider.
Example of Using the ObservedBy
Attribute
Step 1: Create an Observer
First, create an observer using the Artisan command:
php artisan make:observer ProductObserver --model=Product
This will generate a new observer class in the app/Observers
directory. The observer can contain methods for handling various model events such as created
, updated
, deleted
, etc.
namespace App\Observers;
use App\Models\Product;
class ProductObserver
{
public function created(Product $product)
{
// Logic for when a product is created
}
public function updated(Product $product)
{
// Logic for when a product is updated
}
public function deleted(Product $product)
{
// Logic for when a product is deleted
}
}
Step 2: Attach the #[ObservedBy]
Attribute to the Model
Next, apply the #[ObservedBy]
attribute to the Product
model to link it with the observer.
namespace App\Models;
use App\Observers\ProductObserver;
use Illuminate\Database\Eloquent\Model;
#[ObservedBy(ProductObserver::class)]
class Product extends Model
{
// Your model logic here
}
By adding the #[ObservedBy]
attribute, Laravel automatically registers the ProductObserver
for the Product
model, making it unnecessary to manually register the observer in a service provider.
No Need to Register in AppServiceProvider
Previously, observers had to be registered manually in a service provider like this:
use App\Models\Product;
use App\Observers\ProductObserver;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
Product::observe(ProductObserver::class);
}
}
With the #[ObservedBy]
attribute, this step is no longer required. Laravel handles it automatically during the model’s lifecycle.
Benefits of the #[ObservedBy]
Attribute
Improved Readability: The observer is explicitly associated with the model, making the code easier to understand. You can see the observer relationship directly in the model, which improves code navigation and readability.
No Service Provider Boilerplate: You avoid the need for boilerplate code in the
AppServiceProvider
, reducing the setup and maintenance effort.Centralized Logic: All the logic related to the model’s behavior (including observers) is consolidated within the model class.
Example Scenario
Let’s say you have a User
model, and every time a new user is created, you want to send a welcome email. Using the new #[ObservedBy]
attribute, here’s how you would set it up:
Step 1: Create the Observer
php artisan make:observer UserObserver --model=User
In the generated observer:
namespace App\Observers;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
class UserObserver
{
public function created(User $user)
{
Mail::to($user->email)->send(new WelcomeEmail($user));
}
}
Step 2: Attach the #[ObservedBy]
Attribute to the User
Model
namespace App\Models;
use App\Observers\UserObserver;
use Illuminate\Database\Eloquent\Model;
#[ObservedBy(UserObserver::class)]
class User extends Model
{
// Your model logic here
}
Now, whenever a new user is created, the UserObserver
will automatically send a welcome email.
8. Eloquent Accessors and Mutators
Accessors and mutators allow you to modify data before it is retrieved or saved to the database.
Accessor
An accessor allows you to modify how a field is retrieved:
class Product extends Model
{
public function getPriceAttribute($value)
{
return '$' . number_format($value, 2);
}
}
Now, when you retrieve the price
field, it will be formatted with a dollar sign.
Mutator
A mutator allows you to modify how a field is saved to the database:
class Product extends Model
{
public function setPriceAttribute($value)
{
$this->attributes['price'] = $value * 100; // Store price as cents
}
}
9. Timestamps and Soft Deletes
Laravel automatically handles timestamps on models using the created_at
and updated_at
fields. These are updated whenever a record is created or modified.
Disabling Timestamps
If your table doesn’t have these columns, you can disable them:
public $timestamps = false;
Soft Deletes
Soft deletes allow you to "delete" a record without removing it from the database. Instead, the record’s deleted_at
field is updated.
To enable soft deletes, add the SoftDeletes
trait to your model:
use Illuminate\Database\Eloquent\SoftDeletes;
class Product extends Model
{
use SoftDeletes;
}
Make sure to add the deleted_at
column to your migration:
$table->softDeletes();
Now, when you delete a record, it will remain in the database but won’t be retrieved in queries unless explicitly included.
10. Conclusion
Laravel models are the key to interacting with your database using clean, readable code. Eloquent ORM makes it easy to query and manipulate data, while also offering advanced features like relationships, accessors, mutators, and soft deletes. By understanding these fundamental concepts, you can build efficient and maintainable data-driven applications.
This concludes our Laravel Models 101 guide. With these basics under your belt, you can start building sophisticated applications that manage complex data with ease.
Happy coding!
Subscribe to my newsletter
Read articles from Samuel Agyei directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Samuel Agyei
Samuel Agyei
I am a full-stack developer. I am passionate about programming in general. I love to read documentaries and code