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:
- Instead of using
protected $guarded = [];we could specify the fillable ones withprotected $fillable = ['title', 'body'];. - We could use
Page::create($request->only('title', 'body'));here instead of thevalidated()function. - 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?