Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

JohnRivs's avatar

Do I really need to use protected $fillable if...

If I always create and update Eloquent models like

User::create([
    'name' => $request->name
]);

and

$user = User::find(1);

$user->name = $request->name;

$user->save();

but never

User::find(1)->update($request->all());

Do I need to declare the fillable fields or can I get away with protected $guarded = [];?

0 likes
13 replies
ejdelmonico's avatar

$guarded functions like a blacklisting and $fillable as a whitelisting. Making all things mass assignable is probably ok in some instances, but the protection is there for a good reason.

1 like
JohnRivs's avatar

@ejdelmonico Thanks for your reply, but that's not what I'm asking for.

I wanna know if I can just do protected $guarded = []; since I don't pass $request->all() to create() or update(), because it bothers me going back to the fillable property each time I add a new column to the table.

jekinney's avatar

You can. Only eloquent uses those. Any other or force create() etc will by pass it. Keep in mind, sounds lazy and/or lack of planning (I say that only because I interview a lot of developers and looking at code that is inconsistent or over complicated is a red flag).

But as stated I hope you have other ways to ensure proper sanitation of data. No fillable doesn't do it all, just a tool.

JohnRivs's avatar

@jekinney Could you clarify the second part?

As far as I know, $fillable doesn't perform any kind of sanitation. Maybe I understand something else by 'sanitation'.

It only makes sure fields that are not declared in the array never hit the database, which is what I'm manually doing each time I use create() and update(). So it seems kinda redundant.

I don't see the laziness either. I'm making sure I decide what gets through each time I interact with the database. In this particular case (not using $request->all()), it's inconvenient going back to $fillable all the time.

Same with the inconsistent part. It's the opposite; I always create and update like that.

mercuryseries's avatar
Level 17

You can do it if you know that you always specify explicitly your attributes. By the way, even Taylor Otwell or Adam Wathan uses that protected guarded = [];. See this podcast: http://www.fullstackradio.com/52 ).

I rather prefer to use $fillable because I feel more safe.

1 like
milon's avatar

In your scenario, where you never use $request->all(), you don't need to use $fillable or $guarded.

1 like
JohnRivs's avatar

@milon ohh I can even get rid of $guarded too? Well that's even better. Thanks!

JohnRivs's avatar

@mercuryseries Yeah, I've seen them and Jeffrey doing it, that's why I made this thread. I wanted to confirm that I could also get rid of those properties with the way I do things.

1 like
mercuryseries's avatar

@milon How do you do that without $fillable and $guarded?

I think that @JohnRivs will get a MassAssignmentException for example with:

User::create([
    'name' => $request->name
]);

because the argument here is an array and that's what $request->all() returns.

JohnRivs's avatar

@milon Actually I think @mercuryseries might be right. The base Eloquent model comes with protected $guarded = ['*'];. Overriding it with an empty array will do just fine for me.

jekinney's avatar

Create() is an eloquent method which case you need to set guarded or fillable.

Any query builder and newing up the model and explicitly setting each object then call the save() method doesn't utilize eloquent. Also as I stated above forceCreate() will use eloquent but bypass fillable and guarded.

I meant it's a tool of many to help sanitize data. Obviously don't want any user input just saved in the db or if they try and crashes the site (unhandled error) where anything not set in fillable is just ignored and things just keep working with a lot less effort then this post. :)

JohnRivs's avatar

Create() is an eloquent method which case you need to set guarded or fillable.

And I'm gonna set $guarded to an empty array because I'm explicitly declaring which columns are being filled at the time of creation or update.

Any query builder and newing up the model and explicitly setting each object then call the save() method doesn't utilize eloquent.

Newing up an Eloquent model instance or fetching an existing model and calling the save method, most definitely utilize Eloquent. Every example I use in my first post uses Eloquent.

Also as I stated above forceCreate() will use eloquent but bypass fillable and guarded.

Or you can write protected $guarded = []; once and avoid prepending 'force' every time.

I meant it's a tool of many to help sanitize data.

Again, maybe I don't know what that word means, but fillable and guarded don't peform sanitation on the data. Those are not the ones responsible for escaping the input, for example. When it comes to the actual data being written to the database, it doesn't matter if you use them. They just do the white/blacklisting.

In a scenario where the payload only carries the 'name' field, this

class User extends Model {
    protected $fillable = ['name'];
}

User::find(1)->update($request->all());

will write the same thing in the database as

class User extends Model {
    protected $guarded= [];
}

User::create([
    'name' => $request->name
]);

And if there's something missing it'll be caught by the validation part.

In real life projects, business rules tend to require a bit more than just ($request->all()). A lot of times you have to check for something else first or apply some kind of logic to decide if a create or update can happen.

1 like

Please or to participate in this conversation.