Home > Article > PHP Framework > A smart way to handle request validation in Laravel
Laravel is the PHP framework for Web Craftsman. This helps us build powerful applications and APIs. As many of you know there are many ways to validate requests in Laravel. Handling request validation is a very important part of any application. Laravel has some great features that handle this problem very well.
Getting Started
Most of us are familiar with using validators in controllers. This is the most common way to handle validation of incoming requests.
Here is what our validator looks like UserController
<?php namespace App\Http\Controllers\API\v1\Users; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use Illuminate\Support\Facades\Validator; use App\Entities\Models\User; class UserController extends Controller { public function store(Request $request) { // validate incoming request $validator = Validator::make($request->all(), [ 'email' => 'required|email|unique:users', 'name' => 'required|string|max:50', 'password' => 'required' ]); if ($validator->fails()) { Session::flash('error', $validator->messages()->first()); return redirect()->back()->withInput(); } // finally store our user } }
Validating in the controller
There is no problem validating the incoming request in the controller , but this is not the best approach and your controller will look messy. In my opinion this is bad practice. The controller should only handle one processing request from the route and return an appropriate response.
Writing validation logic in the controller will break the single responsibility principle. We all know that requirements change over time, and every time the requirements change, so will your class responsibilities. Therefore, having a lot of responsibilities in a single class makes management very difficult.
Laravel has form requests, a separate request class that contains validation logic. To create one, you can use the Artisan command.
php artisan make: Request UserStoreRequest
This will create a new Request class app\Http\Request\UserRequest
<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class UserStoreRequest extends FormRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return true; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ 'email' => 'required|email|unique:users', 'name' => 'required|string|max:50', 'password' => 'required' ]; } /** * Custom message for validation * * @return array */ public function messages() { return [ 'email.required' => 'Email is required!', 'name.required' => 'Name is required!', 'password.required' => 'Password is required!' ]; } }
Laravel Form Request class has two default methods auth( ) and rules(). You can perform any authorization logic in the auth() method regardless of whether the current user is allowed to request. In the rules() method you can write all the validation rules. There is also a method messages() to pass your own array of validation messages.
Now change our UserController to use our UserStoreRequest. You can enter the prompt for our request class and it will automatically parse and validate before calling our controller function.
<?php namespace App\Http\Controllers\API\v1\Users; use App\Http\Controllers\Controller; use App\Http\Requests\UserStoreRequest; class UserController extends Controller { public function store(UserStoreRequest $request) { // Will return only validated data $validated = $request->validated(); } }
So our controller is now slim and easy to maintain. Now our controller doesn't need to worry about any validation logic. We have our own validation class with only one responsibility to handle validation and let the controller work there.
If verification fails, it will redirect the user to the previous location and display an error. Depending on your request type an error message will flash in the session. If the request is AJAX, a response will be returned with a 422 status code and a JSON-formatted error.
Return
Keep your application and users safe by sanitizing input. Use a cleaner in your application and it will ensure that the data is always well-formatted and consistent. In many cases, validation fails due to silly formatting errors.
The mobile phone number entered by the user is 99-9999-999999 or 99-(9999)-(999999). This is a very common mistake and we cannot force our users to re-enter the same details again.
Some other examples are if the user enters an email as Foo@Bar.COM or FOO@Bar.com. Or enter first and last name, like FOO **bAR or foo baR**
Sanitizer Contains methods to transform and filter data in a common format before feeding it to the validator.
I'm using the Waavi/Sanitizer package which contains many filters.
Waavi / Data Cleaning
Let us create abstract class BaseFormRequest for Form Request and use SanitizesInput trait here.
<?php namespace App\Http\Requests; use Illuminate\Contracts\Validation\Validator; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Http\Exceptions\HttpResponseException; use Illuminate\Http\JsonResponse; use Waavi\Sanitizer\Laravel\SanitizesInput; abstract class BaseFormRequest extends FormRequest { use ApiResponse, SanitizesInput; /** * For more sanitizer rule check https://github.com/Waavi/Sanitizer */ public function validateResolved() { { $this->sanitize(); parent::validateResolved(); } } /** * Get the validation rules that apply to the request. * * @return array */ abstract public function rules(); /** * Determine if the user is authorized to make this request. * * @return bool */ abstract public function authorize(); }
So now we can write the following content of UserStoreRequest. Extend your form requests from our base class so we don't have to include traits in all request classes.
<?php namespace App\Http\Requests; class UserStoreRequest extends BaseFormRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return true; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ 'email' => 'required|email|unique:users', 'name' => 'required|string|max:50', 'password' => 'required' ]; } public function messages() { return [ 'email.required' => 'Email is required!', 'name.required' => 'Name is required!', 'password.required' => 'Password is required!' ]; } /** * Filters to be applied to the input. * * @return array */ public function filters() { return [ 'email' => 'trim|lowercase', 'name' => 'trim|capitalize|escape' ]; } }
SanitizesInputtrait provides a filters() method to format our request data before providing it to the validator. The filters() method returns an array of valid filters. Here we convert the user email to lowercase and trim the same way we converted the name to uppercase and escape any HTML tags.
You can learn more about the available filters here.
Conclusion
First of all, it seems that there is no need to make separate request classes for everyone. But imagine putting all validation logic in the same controller. It's like a bad nightmare - when it comes to managing your code, how much worse is it if someone else has to manage it? .
Thank you for reading.
I'd like to hear your opinion on this. If you have any questions or suggestions, please leave a comment below.
Have a nice day.
For more Laravel related technical articles, please visit the Laravel Framework Getting Started Tutorial column to learn!
The above is the detailed content of A smart way to handle request validation in Laravel. For more information, please follow other related articles on the PHP Chinese website!