Laravel 5.8: Validation multiple inputs - laravel

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

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');
}
});
}

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

Related

Livewire validate function got stuck on unique validation

I'm trying to validate a field for unique value. The validate function throws proper validation errors When I enter incorrect/duplicate values but the execution got stuck in validate method and not coming below to dd('save called') when I enter correct/unique values.
I have tried protected $rules[], and protected function rules() but result is the same.
Note: when I remove the unique rule from validation then everything works fine.
here is component code.
public function savePaper($rowIndex)
{
$this->validate([
'rows.*.p1' => ['required', Rule::unique('dutysheets', 'p1')->ignore($this->row['id'])],
]);
dd('save called');
$row = $this->rows[$rowIndex] ?? NULL;
if (!is_null($row)) {
optional(DutySheet::find($row['id']))->update($row);
}
$this->editedRowIndex = null;
$this->editedPaper = null;
}
and here is the view code.
#foreach ($rows as $index => $row)
<tr>
<td scope="row">
<input type="number" style="max-width: 60px;"
wire:model.differ="rows.{{ $index }}.p1"
wire:click="editPaper({{ $index }}, 'p1')"
wire:keydown.enter="savePaper({{ $index }})"
/>
#if ($editedPaper === $index . '.p1')
#error('rows.' . $index . '.p1')
<div class="alert alert-danger">
{{ $message }}
</div>
#enderror
#endif
</td>

Laravel 5 not displaying validator errors message after redirection

Error messages are not showing.I added the redirection in
sendFailedLoginResponse it is redirecting to the login page without error messages
protected function sendFailedLoginResponse(Request $request)
{
return redirect()->route("login")->withErrors([
$this->username() => [trans('auth.failed')],
]);
}
Blade
<div class="form-group col-md-12">
<input id="email" name="email" class="" type="email" placeholder="Your Email">
#if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('email') }}</strong>
</span>
#endif
return redirect()->route("login")->withErrors(['email' => trans('auth.failed')]);
Instead of array pass a message bag object like this.
$errors = new Illuminate\Support\MessageBag;
$errors->add('email', trans('auth.failed'));
return redirect()->route("login")->withErrors($errors);
The name of the input field should be the second argument of the withErrors() function.
Laravel documentation - Manually Creating Validators
protected function sendFailedLoginResponse(Request $request)
{
return redirect()->route("login")->withErrors(trans('auth.failed'), 'login');
}
Blade file
<div class="form-group col-md-12">
<input id="email" name="email" class="" type="email" placeholder="Your Email">
#if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->login->first('email') }}</strong>
</span>
#endif
If Your application is too large folow these steps
While You are making the validation there are several ways
Method one
Using Validator Facade
public function store(Request $request)
{
$input = $request->all();
$validator = \Validator::make($input, [
'post_name' => 'required',
'post_type' => 'required',
]);
if ($validator->fails()) {
return redirect()->back()
->withErrors($validator)
->withInput($input);
}
Post::create($input);
return redirect('post.index');
}
Method Two
using $this->validate(); Method
public function store(Request $request)
{
$this->validate($request, [
'post_name' => 'required',
'post_type' => 'required',
]);
Post::create($request->all());
}
Method Three
Using the request method
php artisan make:request PostStoreRequest
anf the file will be creted in app\Http\Requests with name PostStoreRequest.php
open you controller and add
use App\Http\Requests\PostStoreRequest;
now the file contents
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class PostStoreRequest 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 [
'post_name' => 'required',
'post_type' => 'required',
];
}
/**
* Custom message for validation
*
* #return array
*/
public function messages()
{
return [
'post_name.required' =>'Enter Post Name',
'post_type.required' =>'Enter Post Type',
];
}
}
if You want to customize the error message use messages function
now the store function
public function store(PostStoreRequest $request)
{
Post::create($request->all() );
return redirect()->route('post.index')->with('success','CrmHfcImageGallery Created Successfully');
}
now Comming to the view
to view all the messages add this in top of the blade file
#if ($errors->any())
{{ implode('', $errors->all('<div>:message</div>')) }}
#endif
To view particular message
<div class="col-sm-4">
<div class="form-group #if ($errors->has('post_name')) has-error #endif">
{!! Form::label('post_name','Post Name') !!}
{!! Form::text('post_name',old('post_name'),['placeholder'=>'Enter Post Name ','class' =>'form-control rounded','id' =>'post_name']) !!}
#if ($errors->has('post_name'))
<p class="help-block">{{ $errors->first('post_name') }}</p>
#endif
</div>
</div>
Hope it helps

Laravel return flash message

I am trying to return a flash message depending on the outcome of an function however I don't really know how to do this properly, can someone help me with fixing this?
Controller:
public function postDB(Requests\NameRequest $request) {
$newName = trim($request->input('newName'));
$newLat = $request->input('newCode');
$websites = new Website();
$websites->name = $newName;
$websites->html = $newLat;
$websites->save();
if ($websites->save())
{
$message = 'success';
}else{
$message = 'error';
}
return redirect()->back()->withInput()->with('message', 'Profile updated!');
}
Request:
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'img' => 'file|image',
];
}
public function messages()
{
return [
'img.image' => 'File type is not supported! Use files with extension .jpg/.jpeg/.gif',
];
}
Template:
#if (session('status'))
#if (session('status')=="success")
<div class="alert alert-success">
{{ session('message') }}
</div>
#else
<div class="alert alert-error">
{{ session('message') }}
</div>
#endif
#endif
Route:
Route::group(['middleware' => ['web']], function () {
Route::get('home', 'BuilderController#homepage');
Route::get('pages', 'BuilderController#websites');
Route::get('template', 'BuilderController#templates');
Route::post('template2', 'BuilderController#postDB');
Route::post('template', 'BuilderController#testing');
Route::get('logout', 'BuilderController#getLogout');
Route::get('/website/{name}', 'BuilderController#website');
});
Solution :
There could be only one reason for this issue.
The laravel will pass the flash messages only if it's registered inside the middleware web
i.e.,
Route::group(['middleware' => ['web']], function () {
//The back()'s url should be registered here
});
Update :
It seems you need to redirect back with message and inputs
So, You can do like this
if ($request->hasFile('img')) {
$message = 'success';
} else {
$message = 'error';
}
return redirect()->back()->withInput()->->with('message', $message);
Update 2 :
#if (session('status'))
#if (session('status')=="success")
<div class="alert alert-success">
Congrats! Everything was fine
</div>
#else
<div class="alert alert-error">
Oops! Something went wrong
</div>
#endif
#endif
Note : You can pass the status param to your wish
If you pass message as a flash parameter name, use it, not status.
#if (session('message'))
#if (session('message')=="success")
<div class="alert alert-success">
Congrats! Everything was fine
</div>
#else
<div class="alert alert-error">
Oops! Something went wrong
</div>
#endif
#endif

laravel pass validation error to custom view

I created a validation but cant show it on view, its important to return search view and don't redirect back user. help me please, thanks all?
Controller :
public function search(Request $request)
{
$msg = Validator::make($request->all(), [
'search' => 'required'
]);
if ($msg->fails()) {
return view('layouts.search')->withErrors($msg->messages());
} else {
return "Thank you!";
}
}
View :
#if($errors->any())
<ul class="alert alert-danger">
#foreach($errors as $error)
<li> {{$error}} </li>
#endforeach
</ul>
#else
You can use $error->first('name_of_error_field') to show error messages.
You can do it like this:
public function search(Request $request)
{
$validator = Validator::make($request->all(), [
'search' => 'required'
]);
if ($validator->fails()) {
return view('layouts.search')->withErrors($validator); // <----- Send the validator here
} else {
return "Thank you!";
}
}
And in view:
#if($errors->any())
<ul class="alert alert-danger">
#foreach($errors as $error)
<li> {{$error->first('name_of_error_field')}} </li>
#endforeach
</ul>
#endif
See more about Laravel Custom Validators
Hope this helps

Combine all NotBlank error messages in Symfony2

I'm trying to combine all NotBlank error messages into one.
If the error array contains at least 1 error that is a NotBlank type, I want it to display only one message like "Please fill in all fields."
How can I do this?
Here's my twig code
{{form_start(form, {'attr': {'novalidate': 'novalidate'}})}}
<div>
{{form_widget(form.firstName)}}
{{form_widget(form.lastName)}}
</div>
<div>
{{form_widget(form.username)}}
{{form_widget(form.email)}}
</div>
<div>
{{form_widget(form.password.first, {'attr' : { 'placeholder' : 'Password' } })}}
{{form_widget(form.password.second, {'attr' : { 'placeholder' : 'Confirm Password' } })}}
</div>
<div>
{{form_label(form.birthday)}}
</div>
<div>
{{form_widget(form.birthday)}}
</div>
<div>
{{form_widget(form.gender)}}
</div>
<div>
{{form_widget(form.save)}}
</div>
{{ form_errors(form.firstName) }}
{{ form_errors(form.lastName) }}
{{ form_errors(form.username) }}
{{ form_errors(form.email) }}
{{ form_errors(form.password.first) }}
{{form_end(form)}}
You can create a CallbackValidator
http://symfony.com/doc/current/reference/constraints/Callback.html
and in the validate method, check if at least one of the desired fields is blank, and if true, call
/**
* #Assert\Callback
*/
public function validate(ExecutionContextInterface $context)
{
if(empty($this->field1) || empty($this->field2)) {
$context->addViolation($message);
}
}
This way you will receive a global form error.

Resources