model

Secure Your Laravel Models with Model::shouldBeStrict()

user

Sonu Singh

16 Apr 2024

12 min read

Laravel MySql PHP

In the world of Laravel development, making sure your data is accurate and protected is super important. That's where Model::shouldBeStrict() comes in. It's like a security guard for your data, making sure everything is in order and catches any mistakes before they cause problems. This helps you build stronger, more reliable Laravel applications.

A Guide to Model::shouldBeStrict()

Imagine you're building a house (your Laravel application). You're excited to get the walls up and furniture in (coding the features), but before you do, you need a strong foundation (data integrity and security). That's what Model::shouldBeStrict() is like for your Laravel app. It helps make sure your data is accurate and protected, preventing problems down the road.

What is Model::shouldBeStrict()

Introduced in Laravel, Model::shouldBeStrict() is a powerful tool that enables stricter data validation for your Eloquent models. By enabling it globally in your application's bootstrap process, you can enforce three key checks:

  1. Preventing Lazy Loading: This safeguards against potential performance issues by catching attempts to lazily load relationships when lazy loading is disabled.
  2. Preventing Silently Discarded Attributes: When mass assigning data using fill() or update(), shouldBeStrict() throws an exception if you try to update attributes that aren't defined in the model's fillable property. This helps prevent unintended data changes.
  3. Preventing Accessing Missing Attributes: With strict mode on, attempts to access non-existent attributes on a model result in an exception, rather than silently returning null. This aids in catching typos and other potential errors.

Why Use Model::shouldBeStrict()?

By enabling strict mode at the beginning of your project, you're setting yourself up for success in several ways:

  1. Early Debugging: Strict mode catches potential problems during development, saving you time and frustration later.
  2. Improved Code Quality: Strict enforcement encourages cleaner code practices by preventing accidental data manipulation.
  3. Enhanced Maintainability: A stricter foundation makes your codebase easier to understand and maintain for yourself and future collaborators.

How to Enable Strict Mode

There are three main ways to enable strict mode for all your models:

  1. In App Service Provider(Globally): Open up app/Providers/AppServiceProvider and go down to boot method
public function boot(): void
{
   Model::shouldBeStrict();
}
  1. In Base Model(Globally): Create a base model class that inherits from Illuminate\Database\Eloquent\Model and overrides the shouldBeStrict() method to return true.

Create a Base model:

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class BaseModel extends Model
{
   protected function shouldBeStrict()
   {
      return true;
   }
}

Extend Other Models from the Base Model:

namespace App\Models;

class User extends BaseModel
{
  protected $fillable = ['name', 'email'];
  // Other user model methods and properties
}
  1. Per-Model Basis: You can enable shouldBeStrict() in individual Eloquent models to ensure strict attribute handling.

Here's how you can do it:

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
  protected $fillable = ['name', 'email'];
  protected function shouldBeStrict()
  {
    return true;
  }
}

In this example, the User model will throw an error if you try to set any attribute that is not name or email.

So when Model::shouldBeStrict() is turned on, it does the following

public static function shouldBeStrict(bool $shouldBeStrict = true)
{
    static::preventLazyLoading($shouldBeStrict);
    static::preventSilentlyDiscardingAttributes($shouldBeStrict);
    static::preventAccessingMissingAttributes($shouldBeStrict);
}

Let's explain all 3 three key checks with an example:

Preventing Lazy Loading Issues:

Let's take an example:

$posts = \App\Models\Post::get();
 
foreach ($posts as $post) {
    echo "<li>" . $post->user->name . "</li>\n";
}

Here it will gives you the expected output. However, Laravel might secretly fetch extra information (like here the user's name) for each post in the loop, even though you might not need it. This can slow things down. Turning on strict mode acts like a helpful friend. It throws an error if your code tries to sneak in these extra queries.

Attempted to lazy load [user] on model [App\Models\Post] but lazy loading is disabled.

Prevent Silently Discarding Attributes

Here let's take an example, trying to update an attribute that is not fillable:

$user->fill(["last_name" => "Doe"]);

So, here turning on Strict Mode, return an exception

Add fillable property [last_name] to allow mass assignment on [App\Models\User].

Prevent Accessing Missing Attributes

  1. Typos: Imagine you have a User model with attributes like name, email. In your code, you loop through users and try to display their profile information:
foreach ($users as $user) {
    echo "Name: " . $user->name . "<br>";
    echo "Email: " . $user->emaill . "<br>"; // Typo! Should be email 
    // ...
}

With strict mode enabled, you'll get an error when trying to access the non-existent emaill attribute. This immediate feedback helps you identify and fix the typo early on, preventing issues down the the line.

  1. Accessing Undefinded Attributes:
$product = Product::find(1);
echo "Additional Info: " . $product->additional_info . "<br>";

However, the additional_info attribute might not be defined yet in your model. By default, Laravel will just not display anything because the property is not found, but with Strict mode turned on you get:

The attribute `[additional_info]` either does not exist or was not retrieved for model [App\Models\Product].

Conclusion

Turning on Model::shouldBeStrict() is now the first thing we shouldI do on every app, and it helps prevent us from making basic mistakes that could be harmful to the app later on.

Share this:

user

Author: Sonu Singh

With over 7 years of dedicated experience in web development, I've traversed through the dynamic landscape of digital technology, honing my skills and expertise across various frameworks and content management systems. My journey began with the exploration of frameworks like CodeIgniter, CakePHP, Yii, and eventually, I found my passion in Laravel - a framework that resonated deeply with my love for elegant, efficient code. Throughout my career, I've had the privilege to contribute to numerous projects, ranging from small-scale ventures to large, enterprise-level solutions. Each project has been a unique opportunity to push boundaries, solve intricate challenges, and deliver innovative solutions tailored to meet client needs. One of my proudest accomplishments includes the development of a SaaS-based project using Laravel and MySQL. This venture not only showcased my technical prowess but also demonstrated my ability to conceptualize, design, and execute scalable solutions that drive business growth. In addition to my proficiency in development, I've also delved into server deployment and query optimization, ensuring that every aspect of a project - from its codebase to its infrastructure - is optimized for peak performance and reliability.

Leave a reply

dot

Subscribe to Newsletter

Provide your email to get email notification when we launch new products or publish new articles

Newsletter

Subscribe to my newsletter to get updated posts

Don't worry, I don't spam