CakePHP 3 Tutorial 21: Conditional Validation

Submitted by naidim on Fri, 01/20/2017 - 12:21

CakePHP's validation is very robust, and while this is immensely helpful, getting to grips with all its possibilities can be daunting.

One handy feature is Conditional Validation. When adding a record, what if we want to ensure a field is not empty only when a matching field is also not empty? For example a schedule for work should have a start time and an end time, but if you wanted to schedule the day off it would have neither.

So how do we ensure that both the start time and end time values are either both not empty, or are both empty?

By default time values in Cake are passed around in an array:


start_time => [
    'hour' => '',
    'minute' => '',
    'meridian' => ''
]

When checking if the field is empty() it will always fail. To prevent this I prefer to set the value to null if it actually is empty.

Add the following to your Model (e.g. src/Model/Table/SchedulesTable.php)


use Cake\Event\Event;
use ArrayObject;

class SchedulesTable extends Table
{
    ...

    public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options)
    {
        // If start_time is empty, set to null
        if (implode($data['start_time']) == '') {
            $data['start_time'] = null;
        }
        // If end_time is empty, set to null
        if (implode($data['end_time']) == '') {
            $data['end_time'] = null;
        }
    }
}

Now in the same Model file add the following to your validationDefault() function:

        $validator
            ->notEmpty('start_time', 'Must have values in both or neither', function($context) {
                return $context['data']?$context['data']['end_time']:false;
            })
            ->notEmpty('end_time', 'Must have values in both or neither', function($context) {
                return $context['data']?$context['data']['start_time']:false;
            });

If the return value is not null (i.e. true), then the checked value must be notEmpty(), otherwise it won't be validated. You can also reverse this using allowEmpty() instead of notEmpty().

Comments

Add new comment