Laravel Validation: Second rule does not run - php

I have this validation in my controller:
$rules = [
'participants' => 'required|atleast_one'
];
Validator::extendImplicit('atleast_one', function ($attribute, $value, $parameters, $validator) {
// Long conditions.
// Returns true or false
});
$error = Validator::make($request->all(), $rules);
The second rule atleast_one is a custom rule using the extend method.
I tested this rule alone and it works. But why is it when I put the two rules together ('participants' => 'required|atleast_one'), the second one doesn't work? I tried rearranging it and still the same, the second rule doesn't work. Did I miss something on the Laravel documentation?

Related

Required field only if another field has a value, must be empty otherwise

My question is about Laravel validation rules.
I have two inputs a and b. a is a select input with three possible values: x, y and z. I want to write this rule:
b must have a value only if a values is x.
And b must be empty otherwise.
Is there a way to write such a rule? I tried required_with, required_without but it seems it can not cover my case.
In other words, if the previous explanation was not clear enough:
If a == x, b must have a value.
If a != x, b must be empty.
You have to create your own validation rule.
Edit app/Providers/AppServiceProvider.php and add this validation rule to the boot method:
// Extends the validator
\Validator::extendImplicit(
'empty_if',
function ($attribute, $value, $parameters, $validator) {
$data = request()->input($parameters[0]);
$parameters_values = array_slice($parameters, 1);
foreach ($parameters_values as $parameter_value) {
if ($data == $parameter_value && !empty($value)) {
return false;
}
}
return true;
});
// (optional) Display error replacement
\Validator::replacer(
'empty_if',
function ($message, $attribute, $rule, $parameters) {
return str_replace(
[':other', ':value'],
[$parameters[0], request()->input($parameters[0])],
$message
);
});
(optional) Create a message for error in resources/lang/en/validation.php:
'empty_if' => 'The :attribute field must be empty when :other is :value.',
Then use this rule in a controller (with require_if to respect both rules of the original post):
$attributes = request()->validate([
'a' => 'required',
'b' => 'required_if:a,x|empty_if:a,y,z'
]);
It works!
Side note: I will maybe create a package for this need with empty_if and empty_unless and post the link here
Required if
required_if:anotherfield,value,...
The field under validation must be present and not empty if the anotherfield field is equal to any value.
'b' => 'required_if:a,x'
Laravel has its own method for requiring a field when another field is present. The method is named required_with.
In Laravel 8+ check if prohibited and prohibited_if validators work for this:
'b' => 'required_if:a,x|prohibited_if:a,!x'

Laravel Validation Rules If Value Exists in Another Field Array

I am working in Laravel 5.4 and I have a slightly specific validation rules need but I think this should be easily doable without having to extend the class. Just not sure how to make this work..
What I would like to do is to make the 'music_instrument' form field mandatory if program array contains 'Music'.
I found this thread How to set require if value is chosen in another multiple choice field in validation of laravel? but it is not a solution (because it never got resolved in the first place) and the reason it doesn't work is because the submitted array indexes aren't constant (not selected check boxes aren't considered in indexing the submission result...)
My case looks like this:
<form action="" method="post">
<fieldset>
<input name="program[]" value="Anthropology" type="checkbox">Anthropology
<input name="program[]" value="Biology" type="checkbox">Biology
<input name="program[]" value="Chemistry" type="checkbox">Chemistry
<input name="program[]" value="Music" type="checkbox">Music
<input name="program[]" value="Philosophy" type="checkbox">Philosophy
<input name="program[]" value="Zombies" type="checkbox">Zombies
<input name="music_instrument" type="text" value"">
<button type="submit">Submit</button>
</fieldset>
</form>
If I select some of the options from the list of check boxes I can potentially have this result in my $request values
[program] => Array
(
[0] => Anthropology
[1] => Biology
[2] => Music
[3] => Philosophy
)
[music_instrument] => 'Guitar'
Looking at validation rules here: https://laravel.com/docs/5.4/validation#available-validation-rules I think something like his should work but i am literally getting nothing:
$validator = Validator::make($request->all(),[
'program' => 'required',
'music_instrument' => 'required_if:program,in:Music'
]);
I was hoping this would work too but no luck:
'music_instrument' => 'required_if:program,in_array:Music',
Thoughts? Suggestions?
Thank you!
Haven't tried that, but in general array fields you usually write like this: program.*, so maybe something like this will work:
$validator = Validator::make($request->all(),[
'program' => 'required',
'music_instrument' => 'required_if:program.*,in:Music'
]);
If it won't work, obviously you can do it also in the other way for example like this:
$rules = ['program' => 'required'];
if (in_array('Music', $request->input('program', []))) {
$rules['music_instrument'] = 'required';
}
$validator = Validator::make($request->all(), $rules);
I know this post is older but if someone came across this issue again.
$validator = Validator::make($request->all(),[
'program' => 'required',
'music_instrument' => 'required_if:program,Music,other values'
]);
You could create a new custom rule called required_if_array_contains like this...
In app/Providers/CustomValidatorProvider.php add a new private function:
/**
* A version of required_if that works for groups of checkboxes and multi-selects
*/
private function required_if_array_contains(): void
{
$this->app['validator']->extend('required_if_array_contains',
function ($attribute, $value, $parameters, Validator $validator){
// The first item in the array of parameters is the field that we take the value from
$valueField = array_shift($parameters);
$valueFieldValues = Input::get($valueField);
if (is_null($valueFieldValues)) {
return true;
}
foreach ($parameters as $parameter) {
if (in_array($parameter, $valueFieldValues) && strlen(trim($value)) == 0) {
// As soon as we find one of the parameters has been selected, we reject if field is empty
$validator->addReplacer('required_if_array_contains', function($message) use ($parameter) {
return str_replace(':value', $parameter, $message);
});
return false;
}
}
// If we've managed to get this far, none of the parameters were selected so it must be valid
return true;
});
}
And don't forget to check there is a use statement at the top of CustomValidatorProvider.php for our use of Validator as an argument in our new method:
...
use Illuminate\Validation\Validator;
Then in the boot() method of CustomValidatorProvider.php call your new private method:
public function boot()
{
...
$this->required_if_array_contains();
}
Then teach Laravel to write the validation message in a human-friendly way by adding a new item to the array in resources/lang/en/validation.php:
return [
...
'required_if_array_contains' => ':attribute must be provided when ":value" is selected.',
]
Now you can write validation rules like this:
public function rules()
{
return [
"animals": "required",
"animals-other": "required_if_array_contains:animals,other-mamal,other-reptile",
];
}
In the above example, animals is a group of checkboxes and animals-other is a text input that is only required if the other-mamal or other-reptile value has been checked.
This would also work for a select input with multiple selection enabled or any input that results in an array of values in one of the inputs in the request.
The approach I took for a similar problem was to make a private function inside my Controller class and use a ternary expression to add the required field if it came back true.
I have roughly 20 fields that have a checkbox to enable the input fields in this case, so it may be overkill in comparison, but as your needs grow, it could prove helpful.
/**
* Check if the parameterized value is in the submitted list of programs
*
* #param Request $request
* #param string $value
*/
private function _checkProgram(Request $request, string $value)
{
if ($request->has('program')) {
return in_array($value, $request->input('program'));
}
return false;
}
Using this function, you can apply the same logic if you have other fields for your other programs as well.
Then in the store function:
public function store(Request $request)
{
$this->validate(request(), [
// ... your other validation here
'music_instrument' => ''.($this->_checkProgram($request, 'music') ? 'required' : '').'',
// or if you have some other validation like max value, just remember to add the |-delimiter:
'music_instrument' => 'max:64'.($this->_checkProgram($request, 'music') ? '|required' : '').'',
]);
// rest of your store function
}
Here my piece of code to solve that kind of trouble usind Laravel 6 Validation Rules
I tried to use the code above
public function rules()
{
return [
"some_array_field.*" => ["required", "integer", "in:1,2,4,5"],
"another_field" => ["nullable", "required_if:operacao.*,in:1"],
];
}
I need that when some_array_field has 1 in your value, another_field must be validated, otherwhise, can be null.
With the code above, doesn't work, even with required_if:operacao.*,1
If I change the rule for another_field to required_if:operacao.0,1 WORKS but only if the value to find is in index 0, when the order changes, validation fails.
So, I decided to use a custom closure function
Here's the final code for the example that works fine form me.
public function rules()
{
return [
"some_array_field.*" => ["required", "integer", "in:1,2,4,5"],
"another_field" => [
"nullable",
Rule::requiredIf (
function () {
return in_array(1, (array)$this->request->get("some_array_field"));
}
),
]
];
}
I hope that solve your trouble too!

Conditional form validation in CakePHP 3

I want to validate some fields from validationDefault() function not all because of conditions but did not find any solution.
Example:
public function validationDefault(Validator $validator) {
$validator
->requirePresence('title', 'create')
->notEmpty('title');
$validator
->requirePresence('inquiry')
->allowEmpty('inquiry');
$validator
->requirePresence('dosage')
->allowEmpty('dosage');
$validator
->requirePresence('dosage_occurance')
->integer('dosage_occurance')
->allowEmpty('dosage_occurance');
return $validator;
}
Note: Response coming from two diffrent form first contains(title and inquiry) other contains(title, dosage and dosage_occurance).
I want to validate it from validationDefault() but it give me error
"dosage_occurance": {
"_required": "This field is required"
}
when I am not sending dosage_occurance which is correct but according to condition it is wrong.
using fieldList while creating new entity but it is not working.
Thanks
You want conditional validation.
Taken from the documentation:
When defining validation rules, you can use the on key to define when a validation rule should be applied. If left undefined, the rule will always be applied. Other valid values are create and update. Using one of these values will make the rule apply to only create or update operations.
Read the whole documentation page.
Example taken from there, pay attention to the on part.
$validator->add('picture', 'file', [
'rule' => ['mimeType', ['image/jpeg', 'image/png']],
'on' => function ($context) {
return !empty($context['data']['show_profile_picture']);
}
]);

CakePHP 3 - Cake trying to validate notEmpty for some reason

My table is throwing a default "notEmpty" validation error, even though I have not written any validation of the sort.
Basic validation in my Table class:
public function validationDefault(Validator $validator)
{
return $validator->requirePresence('my_field', 'create', 'Custom error message');
}
Data being set:
['my_field' => null]
As far as I can tell from the docs, this should not fail validation.
Key presence is checked by using array_key_exists() so that null values will count as present.
However, what is actually happening is that validation is failing with a message:
'my_field' => 'This field cannot be left empty'
This is Cake's default message for the notEmpty() validation function, so where is it coming from? I want it to allow the null value. My database field also allows NULL.
Edit
I have managed to solve the issue by adding allowEmpty() to the validation for that field. This would, therefore, seem to show that Cake assumes that if your field is required you also want it validate notEmpty() by default, even if you didn't tell it so.
This directly contradicts the documentation line I showed above:
Key presence is checked by using array_key_exists() so that null values will count as present.
So does the documentation need to be updated, or is it a bug?
Although it is not mentioned in the Cake 3 documentation, required fields are not allowed to be empty by default, so you have to explicitly state that the field is required and allowed to be empty.
public function validationDefault(Validator $validator)
{
return $validator
->requirePresence('my_field', 'create', 'Custom error message')
->allowEmpty('my_field', 'create');
}
This had me stumped for a while. The default behaviour is not at all intuitive. Here's some code that applies conditional validation on an array of scenarios coded as [ targetField, whenConditionalField, isConditionalValue ]
public function validationRegister()
{
$validator = new Validator();
$conditionals = [ ['shipAddress1','shipEqualsBill','N'], ['shipTown','shipEqualsBill','N'], ['shipPostcode','shipEqualsBill','N'] ];
foreach($conditionals as $c) {
if (!is_array($c[2])) $c[2] = [$c[2]];
// As #BadHorsie says, this is the crucial line
$validator->allowEmpty($c[0]);
$validator->add($c[0], 'notEmpty', [
'rule' => 'notEmpty',
'on' => function ($context) use ($c) {
return (!empty($context['data'][$c[1]]) && in_array($context['data'][$c[1]], $c[2]));
}
]);
}
return $validator;
}
So, in this case, if the user selects that the Shipping Address is not the same as the Billing Address, various shipping fields must then be notEmpty.

cakephp3 custom validation

I have a duration field that sometimes can be empty and sometimes can't, depending on the other data sent by the form. So I'm trying to do custom validation in CakePHP3.
In my table I did
public function validationDefault(Validator $validator)
{
$validator
->add('duration', 'durationOk', [
'rule' => 'isDurationOk',
'message' => 'duration is not OK',
'provider' => 'table'
]);
return $validator;
}
public function isDurationOk($value, $context)
{
// do some logic
return false; // Always return false, just for test
}
Now when I set the value for duration field I get an 'duration is not OK' error (as expected). But when I let the value empty I get a 'This field cannot be left empty' error.
So I added:
->allowEmpty('duration');
But in this case when duration is empty I don't get an error at all.
Am I doing something wrong or it's just me don't understanding how validation works?
Let me read the book for you:
Conditional Validation
When defining validation rules, you can use the on key to define when
a validation rule should be applied. If left undefined, the rule will
always be applied. Other valid values are create and update. Using one
of these values will make the rule apply to only create or update
operations.
Additionally, you can provide a callable function that will determine
whether or not a particular rule should be applied:
'on' => function ($context) {
// Do your "other data" checks here
return !empty($context['data']['other_data']);
}
So just define the conditions depending on your "other data" in the callback to apply the rule only when the conditons are true.
Alternatively you can manipulate the plain form data even before it gets validated in the beforeMarshal() callback of the table and change the form data as needed or load another validator or modify the validator.

Categories