Form array validation in Laravel 5.2

(This is part of a series of posts on New Features in Laravel 5.2. Check back soon for more.)

  1. Form array validation in Laravel 5.2
  2. Implicit route model binding in Laravel 5.2
  3. API rate limiting in Laravel 5.2
  4. Middleware groups in Laravel 5.2
  5. The auth scaffold in Laravel 5.2
  6. Multiple authentication guard drivers (including API) in Laravel 5.2

It's time to start writing about the new features in Laravel 5.2! You'll notice that many of these features are quicker and easier to learn and write up, so it may seem that it's a smaller release. But many of the features in 5.2 will have a big impact on the simplicity and convenience of the code we write day-to-day.

A quick introduction to HTML Form arrays #

Form array validation simplifies the process of validating the somewhat abnormal shape of data HTML forms pass in when the array syntax is used. If you're not familiar with it, a common use case is when you allow a user to add multiple instances of the same type on one form.

Let's imagine you have a form where a user is adding a company, and as a part of it they can add as many employees to the company as they want. Each employee has a name and a title.

Here's our HTML; imagine that we have some JavaScript that creates a new "employee" div every time you press the "Add another employee" button so they user can add as many employees they want.

<form>
    <label>Company Name</label>
    <input type="text" name="name">

    <h3>Employees</h3>
    <div class="add-employee">
        <label>Employee Name</label>
        <input type="text" name="employee[1][name]">
        <label>Employee Title</label>
        <input type="text" name="employee[1][title]">
    </div>
    <div class="add-employee">
        <label>Employee Name</label>
        <input type="text" name="employee[2][name]">
        <label>Employee Title</label>
        <input type="text" name="employee[2][title]">
    </div>
    <a href="#" class="js-create-new-add-employee-box">Add another employee</a>

    <input type="submit">
</form>

If you fill out that form and submit it, this is the shape of the $_POST:

array(2) {
  ["name"]=>
  string(10) "Acme, Inc."
  ["employee"]=>
  array(2) {
    [1]=>
    array(2) {
      ["name"]=>
      string(10) "Joe Schmoe"
      ["title"]=>
      string(11) "Head Person"
    }
    [2]=>
    array(2) {
      ["name"]=>
      string(18) "Conchita Albatross"
      ["title"]=>
      string(21) "Executive Head Person"
    }
  }
}

As you can see, we get an employee "object". And it contains an array of the IDs that we passed in, with the key/value pairs of "fieldname" => "user provided field value".

Note: It used to be common to just set every instance of the "employee name" field, for example, to be just employee[][name] without setting the ID manually. Don't do this. It'll make every aspect of working with the code more complex.

But how do we validate this? Prior to 5.2, it's a bunch of manual work. Now, Laravel understands this nesting structure and can validate against it uniquely.

Writing form array validation rules #

So, how do we do it? Let's take a look at a normal validator:

    // CompaniesController.php
    public function store(Request $request)
    {
        $this->validate($request, [
            'name' => 'required|string'
        ]);
        // Save, etc.
    }

And now let's add validation for our company employee fields:

    // CompaniesController.php
    public function store(Request $request)
    {
        $this->validate($request, [
            'name' => 'required|string',
            'employee.*.name' => 'required|string',
            'employee.*.title' => 'string',
        ]);
        // Save, etc.
    }

Now we're validating every employee[*][name] and employee[*][title] uniquely, with pretty much no effort on our part. Beautiful.

Postscript #

You may have noticed that the shape of the validation is employee.*.name, with an asterisk in the middle, which almost indicates that you could put something else there.

What if, instead of an asterisk to indicate "all", you put a specific number there? Turns out it'll only validate the entities with that ID. So if you put employee.1.name in the validation array instead of employee.*.name, only the employee with the ID of 1 will be validated according to those rules.

I don't know why or when you would do it, but you could actually set completely separate validation rules for each ID:

    $this->validate($request, [
        'employee.1.name' => 'required|string',
        'employee.2.name' => 'integer', // Not sure *why* you would do this, but, it's possible
    ]);

That's it. Enjoy!


Comments? I'm @stauffermatt on Twitter


Tags: laravel | laravel 5.2

Matt Stauffer headshot

Hi, I'm Matt Stauffer.

I'm partner & technical director at Tighten Co.

You can find me on Twitter at @stauffermatt


Like what you're reading?

I wrote an entire 450+ page book for O'Reilly: Laravel: Up and Running.

You can order the eBook or print book today.