required_without_all validator repeats error message over and over - php

I'm building a roster system as a side project and on one of the pages you can change the regular hours someone works.
On the page I have a checkbox for each day of the week, you can then go through and select the appropriate days that the person works.
They need to work at least one day and so at least one of the checkboxes needs to be checked when submitted.
To test this I am using the required_without_all rule of Laravel's validator.
It works perfectly, however if no boxes are checked it will redirect you back and spit out the same error message 7 times (as there are 7 checkboxes for each day of the week).
I am using custom error messages so this is why the error message is the same, but even if I didn't I wouldn't want a similar error message being repeated over and over.
This is what my validator looks like:
$validator = Validator::make($request->all(), [
'mondayCheckbox' => 'required_without_all:tuesdayCheckbox,wednesdayCheckbox,thursdayCheckbox,fridayCheckbox,saturdayCheckbox,sundayCheckbox',
'tuesdayCheckbox' => 'required_without_all:mondayCheckbox,wednesdayCheckbox,thursdayCheckbox,fridayCheckbox,saturdayCheckbox,sundayCheckbox',
'wednesdayCheckbox' => 'required_without_all:mondayCheckbox,tuesdayCheckbox,thursdayCheckbox,fridayCheckbox,saturdayCheckbox,sundayCheckbox',
'thursdayCheckbox' => 'required_without_all:mondayCheckbox,tuesdayCheckbox,wednesdayCheckbox,fridayCheckbox,saturdayCheckbox,sundayCheckbox',
'fridayCheckbox' => 'required_without_all:mondayCheckbox,tuesdayCheckbox,wednesdayCheckbox,thursdayCheckbox,saturdayCheckbox,sundayCheckbox',
'saturdayCheckbox' => 'required_without_all:mondayCheckbox,tuesdayCheckbox,wednesdayCheckbox,thursdayCheckbox,fridayCheckbox,sundayCheckbox',
'sundayCheckbox' => 'required_without_all:mondayCheckbox,tuesdayCheckbox,wednesdayCheckbox,thursdayCheckbox,fridayCheckbox,saturdayCheckbox',
'effective_from' => 'date',
], [
'mondayCheckbox.required_without_all' => 'Surely they are working at least one day!',
'tuesdayCheckbox.required_without_all' => 'Surely they are working at least one day!',
'wednesdayCheckbox.required_without_all' => 'Surely they are working at least one day!',
'thursdayCheckbox.required_without_all' => 'Surely they are working at least one day!',
'fridayCheckbox.required_without_all' => 'Surely they are working at least one day!',
'saturdayCheckbox.required_without_all' => 'Surely they are working at least one day!',
'sundayCheckbox.required_without_all' => 'Surely they are working at least one day!',
'effective_from.date' => 'You have provided an invalid date for when their hours are effective from!',
]);
if ($validator->fails())
{
return Redirect::back()
->withErrors($validator)
->withInput();
}
So if no boxes are checked on submission, the error Surely they are working at least one day! is shown 7 times.
I am displaying the errors on the page like this:
#if (count($errors) > 0)
<div class="alert alert-danger">
<p><b>There were some problems:</b></p>
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
Is there anyway to only get it to show once?

There are many ways to go around this. Since JS hacks are on the table too, we can also come in from the Blade end and do this (feel free to use your own favourite array manipulation functions):
<ul>
<li>
{{-- Show error message only once --}}
#if( $errors->has('mondayCheckbox') || $errors->has('tuesdayCheckbox') || $errors->has('wednesdayCheckbox') || $errors->has('thursdayCheckbox') || $errors->has('fridayCheckbox') || $errors->has('saturdayCheckbox') || $errors->has('sundayCheckbox') )
Surely they are working at least one day!
#endif
</li>
#foreach ($errors->all() as $error)
{{-- Show other errors not related to the checkboxes --}}
#unless($error == 'Surely they are working at least one day!')
<li>
{{ $error }}
</li>
#endunless
#endforeach
</ul>
The other way is to deal with the Illuminate\Contracts\Support\MessageBag in your validator with the After Validation Hook and clean things up there.

It is late but might help someone with similar problem.
Just apply the rule for a hypothetical field, say, weekdays like below.
$validator = Validator::make($request->all(), [
'weekdays' => 'required_without_all:mondayCheckbox,tuesdayCheckbox,wednesdayCheckbox,thursdayCheckbox,fridayCheckbox,saturdayCheckbox,sundayCheckbox',
'effective_from' => 'date',
], [
'required_without_all' => 'Surely they are working at least one day!',
'effective_from.date' => 'You have provided an invalid date for when their hours are effective from!',
]);
And put all the fields (mondayCheckbox.... sundayCheckbox) that you want this rule to be applied after required_without_all. And write the validation message for the rule only once.

You can use array_unique($array) function to remove duplicates from error messages.
Here is the code snippet
#if ($errors->any())
<div class="alert alert-danger">
<ul>
#foreach (array_unique($errors->all()) as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif

Related

Laravel array validation dont show error message

Firstly I can say that after search I dont find any solution about this. I do validation array like this post: laravel validation array
I need validate each size array position. I write this validation code:
// Fields validation
$request->validate([
'name' => 'required|max:150',
'theySay' => 'nullable|array',
'theySay.*' => 'string|max:1000',
'theyDontSay' => 'nullable|array',
'theyDontSay.*' => 'string|max:1000',
]
Where theySay and theyDontSay are both array of strings. In migration I have both fields (text) like strings of 1000 characters.
$table->string('text', 1000);
And validation works correctly. I mean, if put a text greater than 1000 chars I cannot save but..dont show any error message.
I want the error message to be shown in the input just like the rest of the fields.
What am I doing wrong?
Best regards
'YOUR_FIELD' => '...|...|max:1000| ...'
Look at the Laravel validation docs for more information
Please put below code in your blade file for show any error message.
#if ($errors->any())
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif

Laravel validation min and regex being outputted to the same message

I'm having a bit of a weird issue and i'm not quite sure why its happening or if i'm just missing something.
I have multiple validation rules on a input 'postcode' field, like so
'postcode' => [
'required',
'min:5',
'max:8',
'regex:/^[a-z]/i'
],
And i've also wrote custom messages for the rules like so
return [
'postcode.min' => 'The postcode must be at least 5 characters',
'postcode.regex' => 'Sorry, the postcode must start with a letter',
];
All of my errors are being looped and displayed like this
<div class="error-block {{ (count($errors) > 0) ? '' : 'hide' }}">
<div class="col-12">
<ul>
#if(count($errors) > 0)
#foreach($errors->all() as $error)
<li>{{$error}}</li>
#endforeach
#endif
</ul>
</div>
</div>
But when both rules are hit for the postcode, for example with the input '123', then it pushes both errors out on the same line, but all other errors show correctly, like this
The postcode must be at least 5 characters,Sorry, the postcode must start with a letter.
The username field is required.
The address line 1 field is required.
Why is laravel pushing the min and regex rule messages out on the same line?
As described in the docs, validation rules should be expressed as a string, with different rules for a single input separated by a pipe |. The set of inputs to be validated should be an array, but not the rules themselves.
In your case, for the postcode input:
'postcode' => 'required|min:5|max:8|regex:/^[a-z]/i',
That means your $error is an array. if you want to list all error as new line, check if the error is also an array or is not an array.
#if(count($errors) > 0)
#foreach($errors->all() as $error)
#if(is_string($error))
<li>{{$error}}</li>
#else
#foreach( $error as $newBreakdown)
<li>{{$newBreakdown}}</li>
#endforeach
#endif
#endforeach
#endif

Validation errors message on array

Quoting laravel documentation:
Likewise, you may use the * character when specifying your validation messages in your language files, making it a breeze to use a single validation message for array based fields:
'custom' => ['person.*.email' => ['unique' => 'Each person must have a unique e-mail address']]
It seems it does not work. I have a validation message:
'infos.*.*.*' => ['required' => 'My text']
Then I have some inputs in my view:
<input type="text" name="infos[1234][0][name]">
<input type="text" name="infos[1234][1][name]">
<input type="text" name="infos[5678][0][name]">
And in my controller I validate the input:
$this->validate($request, [
'infos.*.*.*' => 'required'
]);
And in view I have a error displayer:
#if (count($errors) > 0)
<strong>Oops. Errors:</strong>
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
#endif
And if I leave all input empty I got:
My text
My text
My text
My text
My text
etc.
What's wrong with my code? Reading Laravel documentation I though it should have worked (I mean: it should have been displayed only once). Did I misunderstood something?
This is working as intended. Since you're passing multiple inputs in an array, the validation throws an error for each item. Therefore 3 inputs with 2 causing errors and 1 passing would obviously pass error for 2 inputs. So in your case the multiple errors are due to multiple inputs failing validation.

Laravel form validation, why I don't have the $errors variable available on my view?

Taken from lrvl 5.1 documentation, I read:
using these lines in the controller:
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'author.name' => 'required',
'author.description' => 'required',
]);
If validation doesn't pass controller stops execution and redirect back to previous location.
This is happening correctly.
Then doc says:
"$errors variable will always be available in all of your views on every request"
And then suggests the following blade code:
#if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
#foreach ($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
But actually I'll get a ErrorException undefined variable errors....
What am I missing?
Thanks
I'll answer myself to this question,
just in case It was not clear the commented solution.
(Thanks to train_fox for the hint).
Just add 'web' middleware usage.
in your routing that is target in form action (get/post)
Example:
Route::group(['middleware' => 'web'],
function(){
Route::post('/edit' , 'My_Controller#edit');
});
Variable $errors the becomes available on view to be parsed.

Laravel 5.2 not showing form validation errors [duplicate]

This question already has answers here:
Undefined variable: errors in Laravel
(9 answers)
Closed 7 years ago.
This is weird. I've been googling all day trying to find a solution for my problem and most of solutions don't work for me due to different versions or different request - controller handling.
What's happening is this.
I have a form:
<div class="form-group">
Name *
{!! Form::text('name', '', ['class'=>'form-control', 'placeholder'=>'Required field']) !!}
</div>
And a Request:
class ContactFormRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|max:64',
'email' => 'required|email|max:128',
'message' => 'required|max:1024',
];
}
}
I'm leaving the name field blank so it fails validation, and it should return to the contact form page and show the errors:
#if(count($errors) > 0)
<div class="alert alert-danger">
<ul>
#foreach($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
</div>
#endif
It shows nothing! If I vardump the $errors variable, I get this:
object(Illuminate\Support\ViewErrorBag)[161]
protected 'bags' =>
array (size=0)
empty
If I fill the form field properly it successfully sends me to the success page and everything works perfect. All I need now is to make this error thing work properly :S
Thank you in advance!
This is a breaking problem with the 5.2 upgrade. What's happening is the middleware which is responsible for making that errors variable available to all your views is not being utilized because it was moved from the global middleware to the web middleware group.
There are two ways to fix this:
1-In your kernel.php file, you can move the middleware \Illuminate\View\Middleware\ShareErrorsFromSession::class back to the protected $middleware property.
2-You can wrap all your web routes with a route group and apply the web middleware to them.
Route::group(['middleware' => 'web'], function() {
// Place all your web routes here...
});
See this
laravel-5-2-errors-not-appearing-in-blade

Categories