Laravel provides a collection of tools for gathering, validating, normalizing. and filtering user-provided data.
Injecting a Request Object
The common tool for accessing user data in Laravel is injecting an instance of the Illuminate\Http\Request
object. It provides easy access to all of the ways users can provide input to our sites: POST, posted JSON, GET, and URL segments.
1 | Route::get('form', function(Illuminate\Http\Request $request){ |
$request->all()
$request->all()
returns an array containing all of the input the user has provided, from every source.
Let’s say we have a form POST to a URL with a query parameter
1 | <form method="post" action="/post-route?utm=12345"> |
$request->except()
and $request->only()
$request->except()
allows you to choose one or more fields to exclude, for example the ‘_token’ filed
1 | <form method="post" action="/post-route?utm=12345"> |
$request->only()
is the inverse of $request->except()
1 | <form method="post" action="/post-route?utm=12345"> |
$request->has()
and $request->exists()
$request->has()
and $request->exists()
could detect whether a particular piece of user input is available to you. The difference is that has()
returns FALSE
if the key exists and is empty; exists()
returns TRUE
if the key exists, even if it’s empty.
request->input()
request->input()
allows you to get the value of just a single field.
1 | Route::post('/post-route', function(Request $request){ |
The second parameter is the default value, so if the user hasn’t passed in a value, you can have a sensible fallback.
Array Input
Laravel also provides convenience helpers for accessing data from array input.
1 | <form method='post' action='/post-route'> |
From Request
Let’s say we have a URL http://www.myapp.com/users/1, $request->segments()
will return an array of all segments, and $request->segment($segmentId)
will return the value of a single segment. The segment has is 1-based index. So $request->segment(1)
will return ‘users’
Uploaded Files
1 | <form method='post' enctype='multipart/form-data' action='form'> |
Validation
Laravel has a few ways to validate request data.
validate() in the Controller Using ValidatesRequests
Out of the box, all Laravel controllers use the ValidatesRequests
trait, which has a convenient validate()
method
We have a route like this:
1 | Route::post('users','UserController@store') |
And the code in controller is
1 | // app/Http/Controllers/UserController.php |
If the data is valid, it will move on to next code. But if the data isn’t valid, it throws a ValidationException
. This contains instructions to router about how to handle this exception. If request is Ajax, the exception will create a JSON response containing the validation errors. If not, the exception will return a redirect to the previous page with all user input and the validation errors for repopulatin a failed form and showing some errors.
Manual Validation
If you are not in a controller, or if for some other reason, you can manually create a Validator
instance to validate request data like this
1 | Route::post('user', function (Illuminate\Http\Request $request){ |
Display Validation Error Messages
The validate()
method in controllers and the withErrors()
method on redirects flashes any errors to the session. These errors are made available to the view you’re being redirected to in the $errors variable. $errors variable will be available every time your load the view, even if it’s empty.
So you can display error like this
1 | @if($errors->any()) |
Form Requests
You may notice that there are certain patterns like vaidation rules, user authentication and authorization are repeated. So you can extract these common behviours out of controller methods.
A form request is a custom request class that is intended to map to the submission of a form, and the request takes the responsibility for validating the request, authorizing the user, and optionally redirecting the user upon a failed validation.
create form request
You can create a new form request using Artisan
1 | php artisan make:request CreateCommentRequest |
You now have a form request object available at app/Http/Requests/CreateCommentRequest.php
Every form request class provides either one or two public methods. The first one is rules()
, which needs to return an array of validation rules for this request, and the second one is authorize()
; if this returns true, the user is authorized to perform this reques, and if false, the user is rejected.
Let’s say we have a route like this:
1 | Route::post('blogPosts/{blogPost}', function(){ // do something}) |
And a request like this
1 |
|
using form request
Now we can user the custome request like this:
1 | Route::post('blogPosts/{blogPost}', function(App\Http\Requests\CreateCommentRequest $request){ |
Eloquent Model Mass Assignment
It’s a common pattern to pass the entirety of a form’s input directly to a database model. In Laravel, that might look like this:
1 | Route::post('/post',function(Request $request){ |
It’s ok if in the request, user have all the field required to create a post, but what if they use their browser tools to add other dummy fileds or set some attribute like author_id to other person?
Eloquent has a concept called ‘mass assignment’ that allows you to either whitelist fields (by set the model’s $fillable
property )that are fillable or blacklist fields that aren’t fillable.
For example we want to protect our author_id, so in our modle class, we can do something like this:
1 |
|
By setting the author_id guarded, we ensure that users will no longer be able to override the value of this field by manually adding it to the contents of a form that they are sending to our app;