Yii2 Rules Validate When Condition - php

I have form fields generated by Yii2 using echo $form->field. When I select 'Pay Now' and submit, the validation should NOT validate the payment person's last name. However, when I select 'Pay Later' and submit, it must validate it as required.
Regardless of what I select, it always treats the field as required. What am I doing wrong?
Select Option:
<select id="singleregisterform-paymentoptionid" name="SingleRegisterForm[paymentOptionId]">
<option value="1">Pay Now</option>
<option value="2">Pay Later</option>
</select>
Text Field:
<input type="text" id="singleregisterform-paymentpersonlastname"
name="SingleRegisterForm[paymentPersonLastname]"
maxlength="40" placeholder="Enter last name">
Yii2 Model Rules:
['paymentOptionId', 'required'],
['paymentPersonTitleId', 'required'],
['paymentPersonLastname', 'string', 'min' => 2, 'max' => 45],
['paymentPersonLastname', 'required', 'when' => function ($model) {
return $model->paymentOptionId == 2;
}, 'whenClient' => "function (attribute, value) {
return $('#paymentOptionId').val() == 2;
}"],

You need to add a ‘whenClient’ rule
https://www.yiiframework.com/doc/guide/2.0/en/input-validation#conditional-validation

Related

Laravel 9 required_if not validating

I'm using Laravel 9 and Livewire 2.0
I have an integer field called 'new_weight' that should validate required if the boolean checkbox 'stripped' is selected. Although 'stripped' is not selected, it's still validating as required. The validation $rules are being hit because if I remove the rule, it doesn't validate at all.
I also recently noticed that if I die and dump '$this->stripped' when the checkbox is selected, it dumps 'true' to the console and not '1', but if I leave unchecked, it dumps '0'--not sure if this matters.
edit.php
...
protected $rules = [
'car_color' => 'required|string',
'new_weight' => 'required_if:stripped,accepted|integer|min:1|max:999',
];
protected $messages = [
'car_color' => 'Please enter car color.',
'new_weight' => 'New Weight Value must be great than 1 but less than 999'
];
...
edit.blade.php
...
<div class="flex items-center h-5">
<input wire:model.defer="stripped" id="stripped" name="stripped"
wire:click="updateStripped"
type="checkbox">
</div>
<div>
<input wire:model.defer="new_weight" id="new_weight" name="new_weight"
type="text"
placeholder="New Vehicle Weight in lbs:">
</div>
...
Since stripped itself is not a rule, I would consider using a custom callback to evaluate the stripped input.
'new_weight' => [
Rule::requiredIf(function () use ($request) {
return $request->input('stripped');
}),
'integer|min:1|max:999'
]
I have this problem too, so I use Rule::when like this and get me same result:
[Rule::when(this->stripped == 'accepted', 'required|integer|min:1|max:999')]
when condition ( this->stripped == 'accepted' ) is true, the rules run
of course if stripped is a check box, you must find out what that's return, so first use dd for that, then replace that with 'accepted' ( I think check box return true and false )
The new_weight field had a default null value in the database. Once I re-migrated with a default empty value, my problem was solved.

Laravel custom validation attribute names with wildcards

When customising Laravel 5.7 validation attributes, is it possible to include wildcards in the attribute names? I can't determine the correct way to indicate a wildcard here.
I have a contacts page which lists the details of a particular contact including all of their phone numbers and emails. From this page you can edit each of these, and add new ones. As such I've used a foreach statement to display each of these and included their id numbers in the form field names, ie:
phone_areacode_{{ $number->id }}
phone_number_{{ $number->id }}
phone_extension_{{ $number->id }}
This makes their names unique and means I can display the error messages relevant only to the specific number or email being edited when validation fails. However, the error messages that display include the number so I get things like "The phone areacode 10 format is invalid." or "The phone number 27 may not be greater than 20 characters."
Is there a way to use wildcards in the attribute names when defining them in the validation language file? Basically I'd like to be able to do this:
'attributes' => [
'phone_areacode_*.*' => 'phone areacode',
],
If not, how can I define the attribute names in the #update method of my controller?
Post values using arrays/objects, and specify validation rules/lang using dot notation:
Example POST data:
{
"phone": {
"ID1234": {
"areacode": "123",
"number": "1231234",
"extension": "1"
}
}
}
Example HTML form (equivalent to POST data above):
<form action="?" method="post">
<input name="phone[ID1234][areacode]" />
<input name="phone[ID1234][number]" />
<input name="phone[ID1234][extension]" />
<input type="submit">Submit</input>
</form>
Example validation:
$validator = Validator::make($request->all(), [
'phone.*.areacode': 'required',
'phone.*.number': 'required',
'phone.*.extension': 'required',
]);
Example lang file:
return [
'attributes' => [
'phone.*.areacode': 'phone area code',
'phone.*.number': 'phone number',
'phone.*.extension': 'phone extension',
],
]);
do you try this way it's from Laravel documentation
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
],

Laravel - Validation - Require if field is null

Let's say I have this html code:
<input type="email" name="email">
<input type="password" name="password">
Or this:
<input type="hidden" name="user_id" value="1">
(If the user is logged in, only the user_id field will be shown. else - the credentials fields).
When I create a request, there's a validation that checks the user. if the field user_id exists (i.e if user_id exists in the users table), then there's no need to require email and password inputs. If there's no user_id, then the email and password fields will be required.
In other words, I want to do something like this:
public function rules()
{
return [
'user_id' => 'exists:users,id',
'email' => 'required_if_null:user_id|email|...',
'password' => 'required_if_null:user_id|...'
];
}
After reading the Validation docs again, I found a solution. I just needed to do the opposite, using the required_without validation:
public function rules()
{
return [
'user_id' => 'exists:users,id',
'email' => 'required_without:user_id|email|unique:users,email',
'password' => 'required_without:user_id',
}

Validate 2 fields should be the same value without one of them has _confirmation in its name in laravel 5

I have debit field and debit field
<input type="text" class="form-control" name="debit" value="{{ isset($expense->debit) ? $expense->debit : old('debit')}}">
and
<input type="text" class="form-control" name="credit" value="{{ isset($expense->credit) ? $expense->credit: old('credit')}}">
i need to make sure the values are equal when submit the form.
i know I can do that if name them like this:
debit and debit_confirmation and in rule array
return Validator::make($data, [
'debit' => 'required|confirmed',
]);
but I don't want to change their names.
any build-in validation in laravel 5 do that.
You could use the same validation rule to match the fields you want.
return Validator::make($data, [
'debit' => 'required|same:credit',
]);
You could take a look at the laravel documentation for more information about validation rules
Among many validators that Laravel offers there is one you're looking for: same. In order to validate if values of 2 different fields (field1, field2) match, you need to define the following rules
$rules = [
'field1' => 'same:field2'
];
You can see a list of all available validation rules here: http://laravel.com/docs/5.1/validation#available-validation-rules

Input validation exclusive or

I have a model called Answer.
This model has two possible relations. A Question or a Product.
But, Answer should only ever have one relation. Either Question or Product.
There is a form to create answers.
This form has three inputs. two of them are <select> inputs. The other is a text input, called name.
I want my validation to only allow one to be filled out.
My current validation:
$validator = Validator::make(
Input::all(),
array('name' => array('required'))
);
$validator->sometimes('product', array('required', 'numeric'), function ($input) {
return !is_numeric($input->question);
});
$validator->sometimes('question', array('required', 'numeric'), function ($input) {
return !is_numeric($input->product);
});
Requires at least one of the selected to be filled out, but will also allow two.
So, my question is: How can I change my validation to only allow one of the selects to be filled out.
But one of them must always be filled out.
Select 1:
<select name="question" class="form-control">
<option>None</option>
<option value="1" selected="selected">Question 1</option>
<option value="2">Question 2</option>
</select>
Select 2:
<select name="product" class="form-control">
<option>None</option>
<option value="2" selected="selected">Product 1</option>
<option value="3">Product 2</option>
</select>
#Razor's custom XOR validation rule is pretty nice, but there's another route if you don't want to create a custom rule. You can add values to Input representing your constraints, using Input::merge, then use those for validation:
Input::merge(array(
'hasBoth' => Input::has('product') && Input::has('question'),
'hasNeither' => !Input::has('product') && !Input::has('question')
));
$validator = Validator::make(
Input::all(), array(
'name' => 'required',
'hasNeither' => 'size:0',
'hasBoth' => 'size:0',
), array(
'hasNeither.size' => 'A question or a product is required.',
'hasBoth.size' => 'You cannot choose both a question and a product.'
)
);
You should still change the empty value in your form to <option value=''>None</option>.
Unlike using an XOR comparison, this method allows you to return separate error messages for no values vs. two values without any further error checking.
First off. You must specify an empty value in "None" option:
<option value=''>None</option>
You are looking for XOR operator, you need to create a custom validation rule in this case:
Validator::extendImplicit('xor', function($attribute, $value, $parameters)
{
if( $value XOR app('request')->get($parameters[0]))
return true;
return false;
});
Validator::replacer('xor', function($message, $attribute, $rule, $parameters)
{
// add indefinite articles
$IAattribute = (stristr('aeiou', $attribute[0]) ? 'an ' : 'a ') . $attribute;
$parameters[0] = (stristr('aeiou', $parameters[0][0]) ? 'an ' : 'a ') . $parameters[0];
if(app('request')->get($attribute))
return 'You cannot choose both '.$IAattribute.' and '.$parameters[0].'.';
return $IAattribute.' or '.$parameters[0].' is required.';
});
$validator = Validator::make(
app('request')->all(),
array('name' => array('required')
,'product' => array('xor:question')
));
The required_without validation rule might be what you want:
The field under validation must be present only when any of the other
specified fields are not present.
Set the question field to required_without:product and the product field to required_without:question.
Answers are a little old now. Today laravel brings some prohibition-rules which will resolve your problems without any hacks.
For your validation that means:
return [
'question' => 'nullable|required_without:product',
'product' => ['nullable',
Rule::prohibitedIf(fn() => $this->question != '')]
Both selects need an item with empty-value, with a text/label you like. Like this:
<select>
<option value="">Foo</option>
</select>
Like this one of the both always need to be set. But its not possible that both are set.
See here: https://laravel.com/docs/9.x/validation#rule-prohibited

Categories