Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

nicolaferrara82's avatar

I need to validate a field which cannot be true if another field is greater than 0

I need to validate a checkbox field that MUST be false if another field is greater than 0, but can be false or true in other situations.The field is passed by request in array.

Example of request form:

'name' => 'Invoice 1',
'number' => 'Inv-001'
'services' => [
	0 => [
		'name' => 'Test 2'
		'vat' => 10.00,
		'unit_price' => 40.00,
		'quantity' => 5,
		'not_taxable' => false
		],
	1 =>  [
		'name' => 'Test 2'
		'vat' => 10.00,
		'unit_price' => 40.00,
		'quantity' => 5,
		'not_taxable' => true
		],
]

In this example I need not_taxable to be false in services[1] if vat is greather than 0. This is my rule for this field :

 'services.*.not_taxable' => 'sometimes:required|boolean',

Rules as required_if, or required_unless etc are not efficient as they do not make any comparisons whether the field is true or false but only if it is passed by the request.

0 likes
10 replies
jlrdw's avatar

services.*.not_taxable could be resolved by some lookup rules, maybe an accessor. I guess I don't understand the validation here.

nicolaferrara82's avatar

I don't think an accessor would be useful in this case, and in frontend there are some js validation rules for this situation.

Imagine a web page where there is a form and many inputs to fill in and different types of taxation,many products/services to choose and attach to invoice, a frontend limitation is easily bypassed, for italian electronic invoices some input fields need more than one condition to be filled and if there is a mistake invoice will be rejected from Interchange System, so i need some guarantees before the invoice is saved.

I think is missing role type true_if or false_if as there are others gt, gte, lt, min, max. Thanks for your help.

jlrdw's avatar

Accessor was just example, you could write a helper class that returns whats needed.

$somevar  = 'taxable' === true ? Helper::return something : $somevar;

Just example. But if I had several situations, I'd probably reach for some helper functions.

nicolaferrara82's avatar

It would have been right if it weren't that my question is about a form submission and validation rules.

Talinon's avatar

@nicolaferrara82

Create a custom rule, loop over the services array and have it return false if it encounters the condition of vat > 0 and not_taxable !== false

Something like:

 'services.*.not_taxable' => [
	'sometimes:required',
	'boolean',
	new NonTaxable
]
namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class NonTaxable implements Rule
{

    public function passes($attribute, $value) : bool
    {

		return 
			$service['vat'] == 0 ||
 			($service['vat'] > 0 && $service['not_taxable'] === false);

    }

}

I think that would work, I've never tried it for arrays.. it should pass each element of the array into the rule object for validation.

If it doesn't work for some reason, then this might:

 'services' => [new NonTaxable]
    public function passes($attribute, $services) : bool
    {

	return ! $services->reject(function ($service) {
		return 
			$service['vat'] == 0 ||
 			($service['vat'] > 0 && $service['not_taxable'] === true);
	})->count();

    }


Basically passes the entire array into the rule object, if a service doesn't pass the truth test, it will remain within the collection. So if the count is greater than 0, the passes() method will return false and the validation will fail. I wouldn't reach for this unless the first example doesn't work.

I obviously haven't test, so you might need to fiddle around with it, but hopefully gives you an idea on how to tackle the validation.

nicolaferrara82's avatar

Thanks @talinon for your reply, now I will make some tests based on your hint.

At the moment I've reached the goal with this :

['sometimes:required', 'boolean', function ($attribute, $value, $fail) {
   $parameters= explode('.', $attribute);
   $vat= (request()[$parameters[0]][$parameters[1]]['vat']);
   if ($value == true && $vat > 0) {
      $fail('Wrong input field.');
   }
}]

but as you can see it looks awful to the eye and needs some refactor.

The strange thing is that phpunit test passes only for the first element of array, but in production it works for all elements.

I will keep you updated

thewebartisan7's avatar

Try apply the custom rule to "services" only. Then $value should be whole services array:



 'services' => [
   'required',
   'min:1',
   'array',
   function($attribute, $value, $fail) {
                    
          // $value is whole $services array, so you can loop over it as Talinon suggest
		   
           return $fail('VAT required');
     }
],
nicolaferrara82's avatar

Yes on whole services array I could loop over it but I think I couldn't highlight the wrong input field on fail because it will return "services" as error key instead of "services.1.not_taxable"

Talinon's avatar

@nicolaferrara82 Does using services.* not work?

I just realized I had an error in my first snippet:

'services.*' => [new NonTaxable]

If you can make that work, I would think it would then include an array of errors including the keys?

I remember having to do something like this once, where I came up with a very hacky solution. I think I resorted to just manually inserting the keys into the array returned from the FormRequest's messages() method.

Upon every failed element, I'd add it to an array, then merge it with the FormRequest's message() array.

// in the loop, keep track of every failed element - pseduo code:

$services->reject(function ($service, $key) {

	if ($logicFails) {
		$this->nonTaxableFailures["not_taxable.{$key}"] = "Taxes required with VAT"; 
	}
});



then merge it within the rules():

    public function messages()
    {
    
        return $this->nonTaxableFailures + [
            'someotherrule' => 'some other message',
            'someotherrule2' => 'some other message2'
        ];
    
    }

Then I just had to make sure I handled the errors on the front end.

There might be an easier way.. my situation was very complex. I'm still surprised if just passing in the array doesn't automatically provide you the formatted errors for free?

1 like
nicolaferrara82's avatar

Yes I think in with this approach I will add some complexity to the project, for the moment I think I will stay on my steps.

A role like false_if or true_if would have been much simpler.

Thanks

Please or to participate in this conversation.