Eloquent Strict Mode in Laravel
Laravel’s Eloquent is a pretty powerful ORM. It allows you to seamlessly interact with your database tables using a simple and expressive syntax. But sometimes, it can be a little too forgiving about the mistakes you make while interacting with the database.
But luckily, Laravel has a little toolkit that can help you prevent these mistakes. Let’s explore them in this article.
- Prevent Lazy Loading
- Prevent Mass Assignment
- Prevent Accessing Non-Existing Attributes
- Enable everything all at once
Prevent Lazy Loading
For instance, it lets you lazy load relationships that might result in the infamous N+1 problem. And this can cause serious performance issues if you’re not careful.
So, let’s say, we have a User
model which has a hasOne
relationship with the Book
model. And we want to fetch all the users along with their books. So, we can do something like this.
$users = User::all();
And then, we can loop through the $users
collection and access the book
relationship like so.
foreach ($users as $user) {
echo $user->book->title;
}
Now, this will work fine. But if you look closely, we’re accessing the book
relationship inside the loop. So, if we have 100 users, this will result in 101 queries. One query to fetch all the users and 100 queries to fetch the books for each user. This is the infamous N+1 problem.
By default, Eloquent doesn’t prevent this and lets you do this. But if you want to prevent this, you can do so by using the Model::preventLazyLoading()
method in the boot
method of your AppServiceProvider
like so.
use Illuminate\Database\Eloquent\Model;
function boot()
{
Model::preventLazyLoading();
}
This will throw a LazyLoadingViolationException
exception if you try to lazy load relationships as we did above.
You can also specify if you want this enabled in specific environments or not. So, for instance, if I don’t want this enabled in the production
environment, I can do so like this.
Model::preventLazyLoading(!$this->app->isProduction());
Prevent Mass Assignment
Another thing that Eloquent is forgiving about is mass assignment. So, let’s say, we have a User
model which has a name
and email
column. And on the User
model, we have a fillable
property that specifies the columns that can be mass assigned like so.
class User extends Model
{
protected $fillable = ['name'];
}
Now, if we try to create a new user like so, it will throw an integrity constraint violation exception because we’re trying to insert a value into the email
column which is not allowed.
User::create([
'name' => 'John Doe',
'email' => '[email protected]'
]);
But the exception is not so helpful. To make it more helpful, we can use the Model::preventSilentlyDiscardingAttributes()
method in the boot
method of your AppServiceProvider
like so.
use Illuminate\Database\Eloquent\Model;
public function boot()
{
Model::preventSilentlyDiscardingAttributes();
}
This will throw a MassAssignmentException
exception if you try to mass-assign attributes that are not allowed.
Prevent Accessing Non-Existing Attributes
Eloquent also lets you access non-existing attributes on the model without throwing any exceptions. So, let’s say, we have a User
model which has a name
and email
column. And we try to access a non-existing attribute like so.
$user = User::first();
echo $user->non_existing_attribute;
This will not throw any exception and will return null
. But if you want to prevent this, you can do so by using the Model::preventAccessingMissingAttributes()
method in the boot
method of your AppServiceProvider
like so.
use Illuminate\Database\Eloquent\Model;
public function boot()
{
Model::preventAccessingMissingAttributes();
}
This will throw an UnknownAttributeException
exception if you try to access non-existing attributes like so.
Enable everything all at once
Now if you want, you can also enable all of the above at once. You can do so by using the Model::shouldBeStrict()
method in the boot
method of your AppServiceProvider
like so.
use Illuminate\Database\Eloquent\Model;
public function boot()
{
Model::shouldBeStrict();
}
Here’s what the method looks like under the hood.
// Illuminate\Database\Eloquent\Model
public static function shouldBeStrict(bool $shouldBeStrict = true)
{
static::preventLazyLoading($shouldBeStrict);
static::preventSilentlyDiscardingAttributes($shouldBeStrict);
static::preventAccessingMissingAttributes($shouldBeStrict);
}
Again, you can also specify if you want this enabled in specific environments or not. So, for instance, if I don’t want this enabled in the production
environment, I can do so like this.
Model::shouldBeStrict(!$this->app->isProduction());
And that’s it. This is how you can enable the strict mode for Eloquent in Laravel.
Like this article?
Buy me a coffee👋 Hi there! I'm Amit. I write articles about all things web development. You can become a sponsor on my blog to help me continue my writing journey and get your brand in front of thousands of eyes.