Understanding Mass Assignment in Laravel Eloquent ORM
Tags: php, laravel, webdev, eloquent
Published: 2020-02-20 07:39:20

---
title: Understanding Mass Assignment in Laravel Eloquent ORM
published: true
description: In this post we will look into Mass Assignment in Laravel Eloquent and life with and without it.
tags: php, laravel, webdev, eloquent
---

[Laravel Eloquent ORM](https://laravel.com/docs/6.x/eloquent) provides a simple API to work with database. It is an implementation of [Active Record](https://www.martinfowler.com/eaaCatalog/activeRecord.html) pattern. Each database table is mapped to a **Model class** which is used for interacting with that table.

#Mass Assignment
Let's break down this word.
* **Mass** means *large number*
* **Assignment** means the *assignment* operator in programming

In order to make developers life easier, Eloquent ORM offers Mass Assignment functionality which helps them **assign**(insert) **large number** of input to database.

##Life, without Mass Assignment 😩
Let's consider that there is a form with 10 fields of user information.

```html
    <form method="POST" action="/signup">
        <input type="text" name="name" />
        <input type="text" name="user_name" />
        <input type="text" name="password" />
        <input type="text" name="address" />
        <input type="text" name="city" />
        ...
        ...
        ...
        <button type="submit">Signup</button>
    </form>
```
and our Controller's store method looks like:
```php
public function store(Request $request)
{
    //perform validation
    
    $user = new User;

    $user->name = $request->get('name');
    $user->user_name = $request->get('user_name');
    $user->password = bcrypt($request->get('password'));
    $user->address = $request->get('address');
    $user->city = $request->get('city');

    //....

    $user->save();
}
```
**We are assigning each input manually to our model and then saving to database.** 

> What if there was a way to insert all the coming input without the manual assignment?

##Life, with Mass Assignment 🥳
Laravel Eloquent ORM provides a **create** method which helps you save all the input with single line.

```php
public function store(UserFormRequest $request)
{
    //validation performed in the UserFormRequest
    
    $user = User::create($request->validated());
} 
```
How cool is that, right? 🤓 With single line we are saving all input to database. In future, if we add more input fields in our HTML form, we don't need to worry about our saving to database part.
> Input fields **name** attribute must match the column name in our database.


##Potential Vulnerability
For the sake of understanding, let's consider that we have an **is_admin** column on **users** table with *true / false* value.

A malicious user can inject their own HTML, a hidden input as below:
```html
    <form method="POST" action="/signup">

        <input type="hidden" name="is_admin" value="1" />

        <input type="text" name="name" />
        <input type="text" name="user_name" />
        <input type="text" name="password" />
        <input type="text" name="address" />
        <input type="text" name="city" />
        ...
        ...
        ...
        <button type="submit">Signup</button>
    </form>
```

With Mass Assignment, **is_admin** will be assigned **true** and the user will have Admin rights on website, which we don't want 😡

##Avoiding the vulnerability
There are two ways to handle this.

* We can specify (whitelist) which columns **can be** mass assigned.

Laravel Eloquent provides an easy way to achieve this. In your model class, add `$fillable` property and specify names of columns in the array like below:
```php
class User extends Model
{
    protected $fillable = [
        'name',
        'user_name',
        'password',
        'address',
        'city'
        ...
    ];
}
```
Any input field other than these passed to **create()** method will throw **MassAssignmentException**.

* We can specify ( blacklist ) which columns **cannot be** mass assigned.

You can achieve this by adding `$guarded` property in model class:
```php
class User extends Model
{
    protected $guarded = ['is_admin'];
}
```
All columns other than *is_admin* will now be mass assignable.
 
> You can either choose `$fillable` or `$guarded` but not both.

So there you have it. Happy Mass Assigning with Laravel Eloquent 🥳 👨🏽‍💻