cespon
cespon

Reputation: 5760

Laravel 5.8: Validation multiple inputs

What I have

I have a form with 3 inputs and I want to check the following conditions:

I resolved this with the following lines.

Controller:

function formAction(Request $request) {
    $this->validate($request, [
        'number1' => 'integer|required',
        'number2' => 'integer|required',
        'number3' => 'integer|required',
    ]);

    $numbers = $request->all();
    $isValid = MyOwnClass::checkMathOperation($numbers);

    if($isValid) {
        return redirect()->route('success');
    } else {
        $request->session()->flash('error', 'The numbers are not valid.');
        return back();
    }
}

View (using Bootstrap):

<form method="POST" action="{{ route('form-action') }}">
    @csrf

    <div class="form-group">
        <label for="number1">number1</label>
        <input id="number1" name="number1" class="form-control {{ $errors->has('number1') ? ' is-invalid' : '' }}" />
    </div>

    <div class="form-group">
        <label for="number2">number2</label>
        <input id="number2" name="number2" class="form-control {{ $errors->has('number2') ? ' is-invalid' : '' }}" />
    </div>

    <div class="form-group">
        <label for="number3">number3</label>
        <input id="number3" name="number3" class="form-control {{ $errors->has('number3') ? ' is-invalid' : '' }}" />
    </div>

    <button type="submit" class="btn btn-primary">Submit</button>
</form>

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

What I looking for

How can I do that with validators?

Solution

Create a Form Request Validation called, for example, NumbersForm using:

php artisan make:request NumbersForm

The previous command creates a App/Http/Requests/NumbersForm.php file. Make authorize() returns true, put the validation rules into rules() and create a withValidatior() function.

class NumbersForm extends FormRequest
{
    public function authorize() {
        return true;
    }

    public function rules() {
        return [
            'number1' => 'integer|required',
            'number2' => 'integer|required',
            'number3' => 'integer|required',
        ];
    }

    public function withValidator($validator) {
        $validator->after(function ($validator) {
            $numbers = $this->except('_token'); // Get all inputs except '_token'
            $isValid = MyOwnClass::checkMathOperation($numbers);

            if(!$isValid) {
                $validator->errors()->add('number1', ' ');
                $validator->errors()->add('number2', ' ');
                $validator->errors()->add('number3', ' ');
                $validator->errors()->add('globalError', 'The numbers are not valid.');
            }
        });
    }
}

Note: It's not important the text in the second param of $validator->errors()->add('number1', ' ');, but it can't be empty. If it is an empty string, $errors->has('number1') returns false, and the field won't be hightlighted.

Set the controller like this:

use App\Http\Requests\NumbersForm;

function formAction(NumbersForm $request) {
    $this->validated();
    return redirect()->route('success');
}

And, finally, if we want to print an unique error message, we must remove the following lines from view:

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

and replace them with:

@if ($errors->has('globalError'))
    <div class="alert alert-danger">
        {{ $errors->first('globalError') }}
    </div>
@else
    @if ($errors->any())
        <div class="alert alert-danger">
            <ul>
                @foreach ($errors->all() as $error)
                    <li>{{ $error }}</li>
                @endforeach
            </ul>
        </div>
    @endif
@endif

Upvotes: 3

Views: 4969

Answers (2)

Kerel
Kerel

Reputation: 732

Custom Validation Rules:

To add custom messages and validation you can also write a custom validation rule

Example:

class Uppercase implements Rule
{
/**
 * Determine if the validation rule passes.
 *
 * @param  string  $attribute
 * @param  mixed  $value
 * @return bool
 */
public function passes($attribute, $value)
{
    return strtoupper($value) === $value;
}

/**
 * Get the validation error message.
 *
 * @return string
 */
public function message()
    {
        return 'The :attribute must be uppercase.';
    }
}

Custom Error Messages:

You could also add custom error messages for rules within a Request:

public function messages()
{
    return [
        'number1.required' => 'My custom message telling the user he needs to fill in the number1 field.',
        'number1.integer' => 'My custom message telling the user he needs to use an integer.',
    ];
}

Upvotes: 0

Full Stack Alien
Full Stack Alien

Reputation: 12501

I haven't tested this but I think it can get you going in the right direction.

1 // Highlight the inputs

You can do this by accessing the error object within your view. This object is an instance of the MessageBag object.

Here is the docs: https://laravel.com/docs/5.7/validation#working-with-error-messages

Example:

// if the error exists for the input the class will be added
<input class=" {{ $error->has('number1') ? 'highlight' : '' }}" name="number1">
<input class=" {{ $error->has('number2') ? 'highlight' : '' }}" name="number2">
<input class=" {{ $error->has('number3') ? 'highlight' : '' }}" name="number3">

2 & 3 // Show a unique custom error message and hide the default messages

See the validator docs: https://laravel.com/docs/5.8/validation#custom-error-messages && https://laravel.com/docs/5.7/validation#working-with-error-messages -- this should solve both of these.

There is a validator callback and I think you can pass your second validation into that. If these numbers aren't valid then you can add your custom error messages and access them the same way as I did above.

function formAction(Request $request) {
    $validator = $this->validate($request, [
        'number1' => 'integer|required',
        'number2' => 'integer|required',
        'number3' => 'integer|required',
    ]);

    $validator->after(function ($validator) {
        $numbers = $request->all();
        $isValid = MyOwnClass::checkMathOperation($numbers);

        if(!$isValid) {
           $validator->errors()->add('number1', 'Unique message');
           $validator->errors()->add('number2', 'Unique message');
           $validator->errors()->add('number3', 'Unique message');
        }
    });
}

Upvotes: 1

Related Questions