Opposite of required_if in laravel using multiple value evaluation - laravel

How to validate must null if another field has specific value or not null
In my case it is the opposite of required_if with multiple values
$rule = array(
'selection' => 'required',
'stext' => 'required_if:selection,2|required_if:selection,3',// stext should be null if selection is 2 or 3
);
And if needed how to perform own validation?

So in your example you can do something like this:
$rule = array(
'selection' => 'required',
'stext' => 'required'
);
// override the rule
if(in_array(request('selection'), [2, 3]))
{
$rule['stext'] = 'nullable';
}
This means if the selection is 2 the field will be required and if the selection field has any other value the stext field will be required.
I am not sure if I understood your question correctly. In any case the opposite of required_if is required_without so you can use that one if you want this field to be required even if the selection is empty.
With custom rule your passes method should look like this:
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class CustomRule implements Rule
{
protected $selection;
public __construct($selection)
{
$this->selection = $selection;
}
public function passes($attribute, $value)
{
return $value === null && in_array($this->selection, [2, 3]);
}
}
You use it like this:
$rule['stext'] = [ new CustomRule(request('selection') ]

I try to extend the validation rule. put the following in AppServiceProvider:
Validator::extend('null_if', function ($attribute, $value, $parameters, $validator) {
$other = $parameters[0];
$other_value = array_get(request()->toArray(), $other);
if ($parameters[1] == $other_value) {
return empty($value);
}
return true;
});
Tell me if it's work or what error given to you.

Related

Laravel - custom validation

I have this validation:
$data = request()->validate([
'qty100' => ['integer'],
'qty250' => ['integer'],
'qty500' => ['integer'],
]);
I would need to check if at least one of them is bigger than 0... how can this be done?
I think there is no built-in validation rule does something like what you want in Laravel, so you'll need to implement a custom validator, that will let you reuse validation where needed.
this is one way of doing it.
request()->validate([
'intone' => ['required', 'integer', 'greaterThanZeroWithoutAll:inttwo,intthree'],
'inttwo' => ['required', 'integer'],
'intthree' => ['required', 'integer'],
]);
in your AppServiceProvider
public function boot()
{
//here we are creating a custom rule. called 'greaterThanZeroWithoutAll'
//$attribute is the name we are validating,
//$value is the value we get from the request,
//$parameters are the arguments we pass in like greaterThanZeroWithoutAll:inttwo,intthree inttwo and intthree are parameters
//$validator is the validator object.
Validator::extend('greaterThanZeroWithoutAll', function ($attribute, $value, $parameters, $validator) {
//$validator->getData() is all the key value pairs from greaterThanZeroWithoutAll rule.
//array_values($validator->getData()) we are only interested in the values, so this will return all the values.
//implode(array_values($validator->getData())) will turn it into string
//!(int) implode(array_values($validator->getData())) this uses no glue when imploding, then explicitly casts the generated string as an integer, then uses negation to evaluate 0 as true and non-zero as false. (Ordinarily, 0 evaluates as false and all other values evaluate to true.)
if (!(int) implode(array_values($validator->getData()))) {
//means all values are 0
return false;
}
return true;
});
// this is error message
Validator::replacer('greaterThanZeroWithoutAll', function ($message, $attribute, $rule, $parameters) {
return 'not all fields are greater 0';
});
}
!(int) implode(array_values($validator->getData())) this code basically checks all the values are zero, there should many other ways to do this.
The reason we only do on the first value is that, we pass the other two values in and compare with it. So, it does it.

Laravel - request validation

I extedned request class to create my own valdiation rules. In that class I added my custom validation function. In function I check if tags are pass regEx and I would like to filter tags to remove tags shorter then 2 characters.
And later keep in request only tags that passed validation.
public function createPost(PostRequest $request)
{
dd($request->all()); //In this place I would like to keep only tags passed through validation not all tags recived in request
}
Is it possibile to do it? How to set it in Request class?
'tags' => [
'nullable',
'string',
function ($attribute, $value, $fail){
$tagsArray = explode(',', $value);
if(count($tagsArray) > 5) {
$fail(__('place.tags_max_limit'));
}
$tagsFiltered = [];
foreach ($tagsArray as $tag){
$tag = trim($tag);
if(preg_match('/^[a-zA-Z]+$/',$tag)){
$tagsFiltered[] = $tag;
};
}
return $tagsFiltered;
}
],
EDIT:
I think we miss understanding. I would like to after validation have only tags that returned in variable $tagsFiltered; Not the same as recived in input.
You have to create this custom regex rule and use it into rules() function.
Like so:
public function rules()
{
return [
'tag' => 'regex:/[^]{2,}/'
];
}
public function createPost(PostRequest $request)
{
$request->validated();
}
And then just call it via validated() function wherever you want.
first define validation rule with this command:
php artisan make:rule TagsFilter
navigate to TagsFilter rule file and define your filter on passes method:
public function passes($attribute, $value)
{
$tagsArray = explode(',', $value);
$tagsFiltered = [];
foreach ($tagsArray as $tag){
$tag = trim($tag);
if(preg_match('/^[a-zA-Z]+$/',$tag)){
$tagsFiltered[] = $tag;
};
}
return count($tagsArray) > 5 && count($tagsFiltered) > 0;
}
then include your rule in your validation on controller:
$request->validate([
'tags' => ['required', new TagsFilter],
]);

Laravel Custom validation rule with parameters

I have write this function rule in CustomRequest to check checkHackInputUser rule that define in provider:
Actually i want to check the value that pass in route
for example :
http://www.somedomain.com/user/{id}
I what do some operation on this $id variable
with my checkHackInputUser rule
Here is CustomRequest:
public function rules()
{
$request_id = $this->route('user');
$rules = [];
if($this->method() == "DELETE" || $this->method() == "GET" )
$rules = [
'role_list' => 'required|checkHackInputUser:'.$request_id,
];
return $rules;
}
The problem is,this rule(checkHackInputUser) doesn't work if i remove required role.
Here is the checkHackInputUser validation function in provider:
public function boot()
{
$this->app['validator']->extend('checkHackInputUser',function($attr,$value,$params){
//Some validation
return false or true;
});
}
You can conditionally validate input when present using sometimes.
In some situations, you may wish to run validation checks against a field only if that field is present in the input array. To quickly accomplish this, add the sometimes rule to your rule list:
$v = Validator::make($data, [
'email' => 'sometimes|required|email',
]);

add Symfony Assert in a Callback

I, i have to add an Assert to an atribute when other atribute is equal than something. Like this:
/**
* #Assert\Callback(methods={"isChildMinor",)
*/
class PatientData
{
/**
* #Assert\Date()
*/
public $birthday;
public $role;
public function isChildMinor(ExecutionContext $context)
{
if ($this->role == 3 && check #assert\isMinor() to $birtday) {
=>add violation
}
}
so, i want check if the patient is minor (with assert or somethings else) if the role is equal than 3. How do this?
There are several ways to do, what you want.
1) You could make it right in the form. Like that:
use Symfony\Component\Validator\Constraints as Assert;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$yourEntity = $builder->getData();
//here you start the field, you want to validate
$fieldOptions = [
'label' => 'Field Name',
'required' => true,
];
if ($yourEntity->getYourProperty != 'bla-bla-bla') {
$fieldOptions[] = 'constraints' => [
new Assert\NotBlank([
'message' => 'This is unforgivable! Fill the field with "bla-bla-bla" right now!',
]),
],
}
$builder->add('myField', TextType::class, $fieldOptions);
2) Other way - is to make your custom validation callback in your Entity and play with direct asserts there. It's possible, I think.
3) But the optimal way, from my point of view - is to use several asserts with validation groups. You need to specify Assert\isMinor(groups={"myCustomGroup"}) on birthday field. And then, in your form:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'validation_groups' => function (FormInterface $form) {
$yourEntity = $form->getData();
if ($yourEntity->role !== 3) {
return ['Default', 'myCustomGroup'];
}
return ['Default'];
},
Hope this'll be helpful for you.

yii2 custom validation not working

I need to compare 2 attribute value in the model and only if first value is lower than second value form can validate.I try with below code but it not worked.
controller
public function actionOpanningBalance(){
$model = new Bill();
if ($model->load(Yii::$app->request->post())) {
$model->created_at = \Yii::$app->user->identity->id;
$model->save();
}else{
return $this->render('OpanningBalance', [
'model' => $model,
]);
}
}
Model
public function rules()
{
return [
[['outlet_id', 'sr_id', 'bill_number', 'bill_date', 'created_at', 'created_date','bill_amount','credit_amount'], 'required'],
[['outlet_id', 'sr_id', 'created_at', 'updated_at'], 'integer'],
[['bill_date', 'd_slip_date', 'cheque_date', 'created_date', 'updated_date','status'], 'safe'],
[['bill_amount', 'cash_amount', 'cheque_amount', 'credit_amount'], 'number'],
[['comment'], 'string'],
['credit_amount',function compareValue($attribute,$param){
if($this->$attribute > $this->bill_amount){
$this->addError($attribute, 'Credit amount should less than Bill amount');
}],
[['bill_number', 'd_slip_no', 'bank', 'branch'], 'string', 'max' => 225],
[['cheque_number'], 'string', 'max' => 100],
[['bill_number'], 'unique']
];
}
}
It's going in to the validator function but not add the error like i wanted
$this->addError($attribute, 'Credit amount should less than Bill amount');
anyone can help me with this?
If the validation is not adding any error, it's most likely being skipped. The issue is most likely becasue of default rules behaviour whereby it skips empty or already error given values as per here: https://www.yiiframework.com/doc/guide/2.0/en/input-validation#inline-validators
Specifically:
By default, inline validators will not be applied if their associated attributes receive empty inputs or if they have already failed some validation rules. If you want to make sure a rule is always applied, you may configure the skipOnEmpty and/or skipOnError properties to be false in the rule declarations.
So you would need to set up the skipOnEmpty or skipOnError values depending on what works for you:
[
['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false],
]
Try this:
public function actionOpanningBalance(){
$model = new Bill();
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$model->created_at = \Yii::$app->user->identity->id;
$model->save();
}else{
return $this->render('OpanningBalance', [
'model' => $model,
]);
}
}
For Validation
You can use anonymous function :
['credit_amount',function ($attribute, $params) {
if ($this->$attribute > $this->bill_amount)) {
$this->addError($attribute, 'Credit amount should less than Bill amount.');
return false;
}
}],
you can use like this below answer is also write
public function rules(){
return [
['credit_amount','custom_function_validation', 'on' =>'scenario'];
}
public function custom_function_validation($attribute){
// add custom validation
if ($this->$attribute < $this->cash_amount)
$this->addError($attribute,'Credit amount should less than Bill amount.');
}
I've made custom_function_validation working using 3rd params like this:
public function is18yo($attribute, $params, $validator)
{
$dobDate = new DateTime($this->$attribute);
$now = new DateTime();
if ($now->diff($dobDate)->y < 18) {
$validator->addError($this, $attribute, 'At least 18 years old');
return false;
}
}
This is a back end validation and it will trigger on submit only. So you can try something like this inside your validation function.
if (!$this->hasErrors()) {
// Your validation code goes here.
}
If you check the basic Yii2 app generated you can see that example in file models/LoginForm.php, there is a function named validatePassword.
Validation will trigger only after submitting the form.

Resources