What Does "Mass Assignment" Mean in Laravel

What does Mass Assignment mean in Laravel?

Mass assignment is when you send an array to the model creation, basically setting a bunch of fields on the model in a single go, rather than one by one, something like:

$user = new User(request()->all());

(This is instead of explicitly setting each value on the model separately.)

You can use fillable to protect which fields you want this to actually allow for updating.

You can also block all fields from being mass-assignable by doing this:

protected $guarded = ['*'];

Let's say in your user table you have a field that is user_type and that can have values of user / admin

Obviously, you don't want users to be able to update this value. In theory, if you used the above code, someone could inject into a form a new field for user_type and send 'admin' along with the other form data, and easily switch their account to an admin account... bad news.

By adding:

$fillable = ['name', 'password', 'email'];

You are ensuring that only those values can be updated using mass assignment

To be able to update the user_type value, you need to explicitly set it on the model and save it, like this:

$user->user_type = 'admin';
$user->save();

Laravel do I have to worry about mass assignment when setting field by field

The purpose of mass assignment protection is to protect developers who source model properties direct from user input, for example:

Example::create($request->input());

Without mass assignment protection a user who knows about the underlying application architecture could inject values into fields they're not expected to have access to, e.g if your User field has an is_admin value they could change their is_admin to 1 instead of 0.

Mass assignment protection is only required when working with unsanitized user input and mass assignment protection is only enabled by default when mass assigning. You have 3 options for a secure application:

  1. Make use of mass assignment and whitelist each property in $fillable
  2. Assign values individually so there is no mass assignment protection, e.g: $user->name = 'John Doe'
  3. Disable mass assignment protection and do not mass assign from user input, e.g:

    protected $guarded = [];

    Example::create($request->only('name', 'age'));

    Example::create(['name' => $request->name, 'age' => $request->age]);

You do not need need to disable mass assignment protection in your example because you are not mass assigning values, you're assigning a value to each property individually. You can determine if you are using mass assignment by asking yourself "Am I passing in an array of properties and their values?".

You can learn more about mass assignment in the Eloquent documentation.

Best way to handle additional fields in mass assignment in Laravel?

You could merge an array with the $validated array:

Venue::create($validated + ['user_id' => auth()->id()]);

This is the same as moving it to the assignment of $validated:

$validated = $request->validated() + ['user_id' => auth()->id()];
Venue::create($validated);

No matter what you would have to merge arrays in some way before this point or at this point if you want this to be done with mass assignment. Otherwise you will be setting individual elements of an array, like you currently are doing.

Mass Assignment issue with `updateOrCreate` in Laravel, why?

First exclude the id from the fields

Second if you want to allow all fields use protected $guarded = []; instead.

Risks of Mass Assignment in Laravel

The "risk" is that developers often pass Input::all() into the model. Without the protection that the new system with $fillable and $guarded provides, unexpected user input can produce an error (to be exact an SQL error like: column foo not in field list) and it possibly allows the user to insert attributes you didn't want him to set by manipulating the request.

Laravel Model::create mass assignment not working for columns with null as default value

Take look at the Mass Assignment Documentation

So, to get started, you should define which model attributes you want to make mass assignable. You may do this using the $fillable property on the model

You have to add $fillable property to your model, especially when you are using Model::create($request->all()).

public $fillable = [];

For example:

public $fillable = ['some_property', 'some_other'];

Now, if you will call create method, 'some_property' and 'some_other' will be assigned.

Also, you can use $guarded which says that all properies are mass assignable and nothing is guarded

public $guarded= [];

Don't use $guarded if you are going to create model by passing $request->all() to create method

Laravel Mass Assignment without id( autoincrement)

Found a solution. Might be helpful if someone else runs into same issue or wants similar results.

Laravel didn't disappoint finally. It allows blank autoincrement fields and does the incrementing by itself( native DB function I think, in my case it's MySQl).
Just have to set 'strict' => false in config/database.php

Laravel eloquent Mass assignment from multi-dimentional array

This is a bit tricky, but you can override fill method in your model, and set deeplyNestedAttributes() for storing attributes thats will be looking for in the request


class Person extends Model {

public $timestamps = false;
public $guarded= ['id'];//Used in order to prevent filling from mass assignment

public function city(){
return $this->belongsTo('App\Models\City', 'city_id');
}

public static function savePerson($request){//Im sending a Request::all() from parameter
$person = isset($request['id']) ? self::find($request['id']) : new self();
$person->fill($request);//This won't work since my $request array is multi dimentional
$person->save();
return $person;
}

public function deeplyNestedAttributes()
{
return [
'city_id',
// another attributes
];
}

public function fill(array $attributes = [])
{
$attrs = $attributes;
$nestedAttrs = $this->deeplyNestedAttributes();

foreach ($nestedAttrs as $attr) {
list($relationName, $relationAttr) = explode('_', $attr);

if ( array_key_exists($relationName, $attributes) ) {

if ( array_key_exists($relationAttr, $attributes[$relationName]) ) {

$attrs[$attr] = $attributes[$relationName][$relationAttr];
}
}
}
return parent::fill($attrs);
}

}


Related Topics



Leave a reply



Submit