Good content takes time and effort to come up with.

Please consider supporting us by just disabling your AD BLOCKER and reloading this page again.







Make Laravel Controllers Slim By Skimming Form Validation Request


Share On     Share On WhatsApp     Share On LinkedIn


Bonjour Les Amis! In this tutorial I will explain you how to separate form validation from controllers and keep in requests class, So that your controllers are slim and you don't clutter too much of things in your controller.


Prerequisites


Working Laravel project or freshly installed Laravel project.


To create fresh Laravel project use the following command:


composer create-project --prefer-dist laravel/laravel project_name

For the sake of demonstration I will be showing User Registration Page. The form fields may not be exactly same as that I have. But this should give you heads up of how to do it.


Normal Class Validation


Usually you do the following ancient way to validate your form in your class.


INITIAL CODE


Here I am taking as INITIAL CODE so that you can compare with FINAL CODE that we will have in the end of this article. You will be really amazed with it.


public static function store()
{
    /** Normal Form Validation */
    request()->validate([
        'name'              => 'required|regex:/^[\pL\s\-]+$/u',
        'gender'            => 'required|in:male,female,other',
        'date_of_birth'     => 'required|date_format:Y-m-d',
        'country'           => 'required|exists:countries,id',
        'state'             => 'required|exists:states,id',
        'city'              => 'required|exists:cities,id',
        'email'             => 'required|email|unique:users,email',
        'phone'             => 'required|digits:10|starts_with:6,7,8,9|unique:users,phone',
        'password'          => 'required',
        'confirm_password'  => 'required|same:password'
    ]);


    try{
        /** Create User Code. I usually put it in Model class. 
            You can directly pass the form request for create, 
            but I am more of no no person for that 
        */
        $user = User::create([
            'name'          => request('name'),
            'gender'        => request('gender'),
            'date_of_birth' => request('date_of_birth'),
            'country_id'    => request('country'),
            'state_id'      => request('state'),
            'city_id'       => request('city'),
            'email'         => request('email'),
            'phone'         => request('phone'),
            'password'      => self::encrypt(request('password')),
        ]);
        if(!$user){
            throw new Exception('Oops! Some error while creating user. Try again.');
        }
        session()->flash('success', 'User Registered Successfully');
        return redirect('/auth/login');
    } catch(\Exception $e) {
        session()->flash('error', $e->getMessage());
        return redirect()->back()->withInput();
    }
}


As you can see in the above example we have form validation & user data adding to database and other code. The controller is cluttered with shit load of code.


Let's Refactor It (Form Requests To Rescue)


Laravel has a feature to move the form requests to separate request class.


Create a CreateUserRequest Class, where we can put all this hell lot of validation code. Use the following artisan command to create the form request in Laravel.


php artisan make:request CreateUserRequest


This creates the CreateUserRequest.php class in app/Http/Requests folder as shown in the following image


CreateUserRequest Form Request Class

CreateUserRequest Form Request Class


Now lets take the user registration form validation from UserController and add the validation in CreateUserRequest class rules() method as follows


class CreateUserRequest extends FormRequest
{
    public function authorize()
    {
        /** Make sure to make this true */
        return true;
    }

    public function rules()
    {
        /** Following is the same validation that you had written in your controller */
        return [
            'name'              => 'required|regex:/^[\pL\s\-]+$/u',
            'gender'            => 'required|in:male,female,other',
            'date_of_birth'     => 'required|date_format:Y-m-d',
            'country'           => 'required|exists:countries,id',
            'state'             => 'required|exists:states,id',
            'city'              => 'required|exists:cities,id',
            'email'             => 'required|email|unique:users,email',
            'phone'             => 'required|digits:10|starts_with:6,7,8,9|unique:users,phone',
            'password'          => 'required',
            'confirm_password'  => 'required|same:password',
        ];
    }

    /** You can customise validation messages here */
    public function messages()
    {
        return [
            'phone.required'    => 'Contact number is required',
            'phone.digits'      => 'Contact number must be numbers',
            'phone.starts_with' => 'Contact number is not valid'
        ];
    }
}


Don't forget to make authorize() function return true. If you want you can even make auth() validation and return true if the user has permission or not


public function authorize()
{
    /** You can check if the user can perform this 
        validation request based on his access. 

        For the sake of simplicity I am returning true here
    */
    /** Make sure to make this true */
    return true;
}


You can customise your validation messages in messages() function as shown below


public function messages()
{
    return [
        'phone.required'    => 'Contact number is required',
        'phone.digits'      => 'Contact number must be numbers',
        'phone.starts_with' => 'Contact number is not valid'
    ];
}

How Do We Use This In Controller


The above CreateUserRequest won't get called automatically we need to inject in UserController store method parameter as follows


use App\Http\Requests\CreateUserRequest;

public function store(CreateUserRequest $request)
{
    /** User Registration Code */
}


Now overall your UserController will look like the following:


use App\Http\Requests\CreateUserRequest;

public static function store(CreateUserRequest $request)
{
    try{
        /** Create User Code. I usually put it in Model class. 
            You can directly pass the form request for create, 
            but I am more of no no person for that 
        */
        $user = User::create([
            'name'          => request('name'),
            'gender'        => request('gender'),
            'date_of_birth' => request('date_of_birth'),
            'country_id'    => request('country'),
            'state_id'      => request('state'),
            'city_id'       => request('city'),
            'email'         => request('email'),
            'phone'         => request('phone'),
            'password'      => self::encrypt(request('password')),
        ]);
        if(!$user){
            throw new Exception('Oops! Some error while creating user. Try again.');
        }
        session()->flash('success', 'User Registered Successfully');
        return redirect('/auth/login');
    } catch(\Exception $e) {
        session()->flash('error', $e->getMessage());
        return redirect()->back()->withInput();
    }
}


This is much cleaner. Isn't it?


Move Business Logic To Model


This is lot of controversial topic ie where to put your business logic. As Taylore Otwell himself said we can put it in Models I usually do it there.


Even we can use the Repository Pattern and segregate lot of code moving to that folder. But in this article lets not argue on that. Let me write another article on the same.


Coming back to our code, once I move the registration code to User Model it will look some what this way


FINAL CODE


Which I am very much satisfied with


use App\Http\Requests\CreateUserRequest;

public static function store(CreateUserRequest $request)
{
    try{
        $user = User::register($request->all());
        if(!$user){
            throw new Exception('Oops! Some error while creating user. Try again.');
        }
        session()->flash('success', 'User Registered Successfully');
        return redirect('/auth/login');
    } catch(\Exception $e) {
        session()->flash('error', $e->getMessage());
        return redirect()->back()->withInput();
    }
}

Conclusion


There is lot of stuff to share with you guys. But as we know everything cant be covered in a single stretch. So stay tuned & keep learning. Don't forget to share with your friends.







Author Image
AUTHOR

Channaveer Hakari

I am a full-stack developer working at WifiDabba India Pvt Ltd. I started this blog so that I can share my knowledge and enhance my skills with constant learning.

Never stop learning. If you stop learning, you stop growing