In the properties of the Eloquent Models, you may find a $fillable
array. By default, in the User
Model, there are three fillable fields.
class User extends Authenticatable{ use HasFactory, Notifiable; protected $fillable = [ 'name', 'email', 'password', ]; // ...}
So, what are fillables, how do they work, and what are the alternatives?
Practical Example
These fields can be provided when creating a new object with Eloquent. What does it mean?
I have a temporary Route with a Controller.
routes/web.php:
Route::get('/', [\App\Http\Controllers\HomeController::class, 'index']);
In the Controller, I have two ways to create a user. The first way is the create method used on the Model and providing values as an array. The second way is to make the object manually, assign the value to each property, and then hit save.
app/Http/Controllers/HomeController.php:
use App\Models\User; class HomeController extends Controller{ public function index() { // First method User::create([ 'name' => fake()->name(), 'email' => fake()->email(), 'password' => bcrypt('password'), 'email_verified_at' => now(), ]); // Second method $user = new User(); $user->name = fake()->name(); $user->email = fake()->email(); $user->password = bcrypt('password'); $user->email_verified_at = now(); $user->save(); }}
Probably, most people like the first method more. Because it is shorter and you don't need to repeat users. Now, let's visit the home page and look at the difference between these two methods, which are related to fillables. Let's check the DB for the users
table.
Two users have been created, but do you see the difference? For the first user, the email_verified_at
field is null. But, when creating a user in both methods, the email_verified_at
is provided. The difference is that this field email_verified_at
isn't added to the $fillable
array.
So, if you want to create records using the first method, by using the create method on the Model, make sure all the fields are in the $fillable
array.
The only exceptions are the id
and created_at/updated_at
timestamps, which are automatically in the fillables, internally from the framework.
Eloquent, Please Be Strict
The worst part of the case above is that Eloquent didn't throw any errors. It just didn't save the field.
But you can tell Eloquent to be stricter with that in the AppServiceProvider
. However, that strictness should only be present in a local environment.
app/Providers/AppServiceProvider.php:
use Illuminate\Support\ServiceProvider;use Illuminate\Database\Eloquent\Model; class AppServiceProvider extends ServiceProvider{ // ... public function boot(): void { Model::shouldBeStrict(! app()->isProduction()); }}
If we try to rerun the home page, we will get a MassAssignmentException
error.
Alternative: $guarded
There is an alternative syntax if you want to avoid adding $fillable
fields for every Model. You can provide the opposite of fillables, called $guarded
.
In the $guarded
array, you can provide an array of fields that will NOT be fillable. So, typically, people leave it as an empty array.
app/Models/User.php:
class User extends Authenticatable{ use HasFactory, Notifiable; protected $fillable = [ 'name', 'email', 'password', ]; protected $guarded = []; // ...}
Now, after trying to visit the home page, we see no errors. Let's check the DB.
Two new users have been created, and both have the email_verified_at
fields filled.
Another place where you can define the non-fillable fields is unguard()
method in the AppServiceProvider.
You don't need to add the $guarded
property in every Model by providing unguard()
in the Provider.
app/Providers/AppServiceProvider.php:
use Illuminate\Support\ServiceProvider;use Illuminate\Database\Eloquent\Model; class AppServiceProvider extends ServiceProvider{ // ... public function boot(): void { Model::shouldBeStrict(! app()->isProduction()); Model::unguard(); }}
thanks