3

What I have

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

  • All inputs are integers and they are required.
  • We do a math operation with all the numbers and we get if the operation was successfull or not.
    • Success: we redirect the user to a success page.
    • No success: we show a error message to the user with a message explaining him that the numbers aren't valid.

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

  • When MyOwnClass::checkMathOperation($numbers) is false:
    • To highlight number1, number2 and number3 inputs.
    • To show an unique custom error message
    • To hide the number1, number2 and number3 input error messages.

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
1

2 Answers 2

1

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');
        }
    });
}
Sign up to request clarification or add additional context in comments.

Comments

0

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.',
    ];
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.