[EN] Laravel 5.5 validated() method on Form Requests

Door 7 oktober 2017Tips & Trucs

A while ago when Laravel 5.5 wasn’t released yet Jeffrey Way started a “What’s New in Laravel 5.5” serie on Laracasts. In the second lesson Streamlined Request Validation Jeffrey introduced us to the validated data array when validating a request:

public function store()
{
    $validatedData = request()->validate([
        'title' => 'required',
        'body' => 'required',
    ]);
}

Normally you would do something like request()->all() which isn’t always save if you’re not setup the mass assignment variables on the model right. For example when you’ve disabled mass assignment by adding protected $guarded = []; to a model. A better way is to use request()->only() with the fields you need. With the above example that would be: request()->only(['title', 'body']) but that’s feels like duplication right? You’ve already defined the fields in the validation array. From Laravel 5.5 $validatedData will output an array with the validated fields, the same as request()->only() would do.

What about Form Requests?

The first thing I was thinking when I’ve watched that lesson; is there something similar when using Form Requests? I’m not a big fan of validating data in my controller. A comment under the lesson brought me here: laravel-validator which introduced that functionality to Laravel 5.4 with:

public function store(FormRequest $request)
{
    Page::create($request->valid());
}

But Laravel 5.5 introduced the validated() method (currently still undocumented) so that package isn’t needed anymore and confirmed by the author. I did find a bug with it but was fixed already in Laravel 5.5.4.

What if not all the data should be saved to the model?

In a project I’m currently working on I’m using Spatie’s Medialibrary package so I’ve rules to validate images and lately I’m using protected $guarded = []; on all my models to disable the mass assignment checks. Let’s say we’ve a page with a title, body and image. In our rules() method on our PageRequest we’ve these rules:

return [
    'title' => 'required',
    'body'  => 'required',
    'image' => 'image'
];

When we save the page with Page::create($request->validated()); we’ll get a database error because there is no image column. Spatie’s Medialibrary saves all the media in a seperated table so we don’t have a image column on our pages table. After we’ve saved the page we’ll process the image.

We’ve a few option to fix this:

  1. Instead of using protected $guarded = []; we could specify the fillable ones with protected $fillable = ['title', 'body'];.
  2. We could use Page::create($request->only('title', 'body')); here instead of the validated() function.
  3. We exclude the image: Page::create(collect($request->validated())->except(['image'])->toArray());

I’m using option 3, it may look like the longest / most complex option but if you’re getting more and more fields you’ll see it’s the easiest because it’s just a blacklist of fields you don’t want. You could refactor this back to your model so the blacklist is defined there.

What option do you prefer?