CakePHP 4 Validation of two fields

A form includes two fields where one must be populated, but only one.

I have written two rules (below), the first works, producing an error when both fields are populated. The second does not, allowing both fields to be empty (when we must have one). What am I missing?

        $validator->add('labor', 'custom', [
            'rule' => function ($value, $context) {
                if (!empty($context['data']['labor']) && !empty($context['data']['flat_rate'])) {
                    return false;
                }
                return true;
            },
            'message' => 'You cannot define both a flat rate and a labor time. Assign labor when parts can be expected.'
        ]);
        
        $validator->add('flat_rate', 'custom', [
            'rule' => function ($value, $context) {
                if (empty($context['data']['labor']) && empty($value)) {
                    return false;
                }
                return true;
            },
            'message' => 'You must define either a flat rate or a labor time. Assign labor when parts can be expected.'
        ]);

Thank you for your help!

When both fields are empty, and the second one is called, what do $value and $context hold?

Sorry for the long delay Zuluru, and you responded so quickly.

Your question helps. This may be a given, I’m still learning. It appears the validator is only called when the field has a value. What I’m trying to do is require one of the two to be populated (both cannot be empty, nor should both be populated). So the first validator (labor) is working as designed (failing if both are populated), but the second (flat_rate) is only called when flat_rate has a value (so it will never fail when both are empty).

Depends on what you mean by “has a value”, I think? Validators are only called when the field is present in the provided data, but the value could be blank. Sounds like maybe what you want is more of a rule than a validation.

I think you’re right. I’ll look at it from that angle, thank you!

I would be writing a Rule rather than a Validator for this.

As the validation documentation explains:

  1. Before request data is converted into entities, validation rules around data types and formatting can be applied.
  2. Before data is saved, domain or application rules can be applied. These rules help ensure that your application’s data remains consistent.

To be clear

  • Validations enforce data types
  • Rules enforce logic

Your case is a clear example of enforcing business rules (logic)

The key advantage in this case is that your Rule will receive the entire entity as one of the arguments and this will make it simple to write the logic you require.

Read about Rules here.

1 Like