Home > database >  How to validate multiple fields selectively using a common class in PHP laravel while returning all
How to validate multiple fields selectively using a common class in PHP laravel while returning all

Time:12-11

Just started with my first PHP laravel project, and I have this

UserRepository.php

public function validateNewEmail(Request $request, $emailName) {
    $request->validate([
        $emailName => ['required', 'email', 'unique:users'],
    ]);
}

public function validateNewPassword(Request $request, $passwordName) {
    $request->validate(
        // rule
        [
            $passwordName => ['required', 'min:8', 
                    'regex: // some long long regex'
        ],
        // message
        [
            $passwordName.".regex" => "Your new password must be more than 8 characters long, should contain at-least 1 uppercase, 1 lowercase, 1 numeric and 1 special character.",
        ]
    );
}

// Usr Id is by itself as it might be optional in registering.
public function validateNewUsrId(Request $request, $userIdName) {
    $request->validate([
        $userIdName => 'required|unique:users',
    ]);
}

And I can then use this repository easily like this in my controller.

$this->userRepository->validateNewEmail($request, "email");
$this->userRepository->validateNewPassword($request, "password");
$this->userRepository->validateNewUsrId($request, "usr_id");

The reason is because there might be multiple controllers that use the same rules, thus putting them in one place is better

However, I realised that this method does not work because it returns the first error only. For example when both the email and password is wrong, only the email error gets returned to the frontend.

What is the best way to achieve what I want? I want to put all my validation/rules in one place to be reused.

My first solution is this: Each function returns the error MessageBag which is then joined together. I will use return $validator->errors(); to return the MessageBag which can be found here https://laravel.com/docs/8.x/validation#retrieving-the-first-error-message-for-a-field

However I slightly dislike it because then in order to check for whether an error occured, I would need to check if MessageBag is empty and then throw an error which seems a little weird.

The other way I thought of is to return the rules instead, so that I can join them in my controller and then validate all in one go. This seems better but I have to combine the error messages as well, which can be a little tricky if there are multiple (since the key is not fixed, see the code $passwordName.".regex" for example.), as I will need to update the key to each message.

The best way for me, is if I could return a validator for each function, and then use some sort of Validate::ValidateAll function? Is that possible?

How is this implemented usually?

CodePudding user response:

Modern Laravel applications typically use form request validation. With this approach, Laravel handles all the validation and returns error messages automatically. Simply write your form request class, and then use it in place of Request in your controller methods:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Password;

class MyFormRequest extends FormRequest
{
    /**
     * Get the validation rules that apply to the request.
     */
    public function rules(): array
    {
        return [
            'email' => ['required', 'email', 'unique:users'],
            'password' => [
                'required',
                Password::min(8)->mixedCase()->numbers()->symbols()
            ],
            'usrid' => ['required', 'unique:users'],
        ];
    }
}
public method store(MyFormRequest $request)
{
    // $request has been validated, no further checking needed
}

Note I'm using Laravel's built-in password validation rules instead of relying on a "long long regex."

  • Related