Reputation: 5732
I am trying to write a validation rule in CakePHP 3 that checks, if the prename and lastname OR the company name is set.
Validators:
$validator
->add('prename', 'custom', [
'rule' => [$this, 'validateName'],
'message' => __('Prename and lastname OR company name must be set.')
]);
$validator
->add('lastname', 'custom', [
'rule' => [$this, 'validateName'],
'message' => __('Prename and lastname OR company name must be set.')
]);
$validator
->add('name', 'custom', [
'rule' => [$this, 'validateName'],
'message' => __('Prename and lastname OR company name must be set.')
]);
Rule definition:
public function validateName($check, array $context)
{
if((!empty($context['data']['prename']) && !empty($context['data']['lastname'])) || !empty($context['data']['name'])){
return true;
} else {
return false;
}
}
But the validation does not behave as expected. If I enter the company name, I get validation errors for prename and lastname saying that the fields is required. Same when I enter the prename and lastname, it says the company name is required.
What am I doing wrong?
Upvotes: 4
Views: 1645
Reputation: 5732
The provided answers all did not work 100%, so I am going to post what I have come up with. I am using conditional validation as described in the CakePHP 3 docs.
CustomersTable.php:
public function validationDefault(Validator $validator)
{
$validator->notEmpty('name', __("Required when prename and lastname is empty."), function ($context) {
return !$context['data']['prename'] && !$context['data']['lastname'];
});
$validator->notEmpty('prename', __('Required when company or lastname is empty.'), function ($context) {
return !$context['data']['name'];
});
$validator->notEmpty('lastname', __('Required if company or prename is empty.'), function ($context) {
return !$context['data']['name'];
});
return $validator;
}
This approach correctly validates the data when it is submitted. However, some browsers say that those fields have to be filled because they are required. To avoid that, we have to define the fields as required => false
:
add.ctp view file:
echo $this->Form->input('prename', [
'label' => ['text' => __('Prename (*): ')],
'required' => false,
]);
echo $this->Form->input('lastname', [
'label' => ['text' => __('Lastname (*): ')],
'required' => false,
]);
echo $this->Form->input('name', [
'label' => ['text' => __('Company name (*): ')],
'required' => false,
]);
Upvotes: 2
Reputation: 1181
I have also faces this type of weird behaviors with cakePhp 3.x.I manage to solve this problem.
Below is the code to solve the asked question
$validator
->notEmpty('company_name', 'Prename and lastname OR company name must be set.', function ($context){
if((!empty($context['data']['prename']) && !empty($context['data']['lastname'])) || !empty($context['data']['name'])){
return false;
} else {
return true;
}
});
$validator
->notEmpty('prename', 'Prename and lastname OR company name must be set.', function ($context){
if((!empty($context['data']['prename']) && !empty($context['data']['lastname'])) || !empty($context['data']['name'])){
return false;
} else {
return true;
}
});
$validator
->notEmpty('lastname', 'Prename and lastname OR company name must be set.', function ($context){
if((!empty($context['data']['prename']) && !empty($context['data']['lastname'])) || !empty($context['data']['name'])){
return false;
} else {
return true;
}
});
I hope this will be the solution for your problem.
Upvotes: 3
Reputation: 481
For this CakePhp provide create custom validation. You need to create two validation function on your model class and call them conditionally on controller function. You can create validation function like as
public function validationName($validator){
$validator
->requirePresence('prename')
->notEmpty('prename', 'Prename must be set.')
->requirePresence('lastname')
->notEmpty('lastname', 'Lastname must be set.')
->allowEmpty('name');
return $validator;
}
public function validationCompany($validator){
$validator
->requirePresence('name')
->notEmpty('name', 'Company name must be set.')
->allowEmpty('prename')
->allowEmpty('lastname');
return $validator;
}
On controller you can call these function conditionally like as
$validator = 'company';
if(empty($this->request->data[''])){
$validator = 'name';
}
$entity = $this->{$this->modelClass}->newEntity();
$entitydata = $this->{$this->modelClass}->patchEntity($entity, $this->request->data, ['validate' => $validator]);
$this->{$this->modelClass}->save($entitydata);
Upvotes: 0
Reputation: 457
We have the following code running in production, which is much alike yours:
$validator
->add('various_fee_text', 'custom', [
'rule' => [$this, 'variousFieldsChecker'],
'message' => __('Udfyld både Tekst og DKK feltet'),
])
->allowEmpty('various_fee_text');
Vaildation rule:
/**
* Method checks whether or not various fee text and various fee prices are either both empty, both set or "dirt",
* meaning only one of them is set and the other is empty. We want either both to be set or both to be empty.
*
* @return bool depending on it's OK or not
*/
public function variousFieldsChecker($value, $context)
{
$varioustext = $context['data']['various_fee_text'];
$variousPrice = $context['data']['various_fee_price'];
if (!empty($varioustext) && !empty($variousPrice)) {
return true;
} elseif ((empty($varioustext) && empty($variousPrice))) {
return true;
}
return false;
}
I think what you need is to append the ->allowEmpty()
like suggested previously.
Upvotes: 0