Get "PHP 8 in a Nuthshell" (Soon includes PHP 8.4)
Amit Merchant

Amit Merchant

A blog on PHP, JavaScript, and more

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

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.

LazyLoadingViolationException

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.

MassAssignmentException

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.

UnknownAttributeException

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.

Learn the fundamentals of PHP 8 (including 8.1, 8.2, and 8.3), the latest version of PHP, and how to use it today with my new book PHP 8 in a Nutshell. It's a no-fluff and easy-to-digest guide to the latest features and nitty-gritty details of PHP 8. So, if you're looking for a quick and easy way to PHP 8, this is the book for you.

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.

Comments?