diff --git a/api/app/Rules/FormPropertyLogicRule.php b/api/app/Rules/FormPropertyLogicRule.php index eb7c280f..a3879123 100644 --- a/api/app/Rules/FormPropertyLogicRule.php +++ b/api/app/Rules/FormPropertyLogicRule.php @@ -42,73 +42,72 @@ class FormPropertyLogicRule implements DataAwareRule, ValidationRule if (!isset($condition['value'])) { $this->isConditionCorrect = false; $this->conditionErrors[] = 'missing condition body'; - return; } if (!isset($condition['value']['property_meta'])) { $this->isConditionCorrect = false; $this->conditionErrors[] = 'missing condition property'; - return; } if (!isset($condition['value']['property_meta']['type'])) { $this->isConditionCorrect = false; $this->conditionErrors[] = 'missing condition property type'; - return; } if (!isset($condition['value']['operator'])) { $this->isConditionCorrect = false; $this->conditionErrors[] = 'missing condition operator'; - - return; - } - - if (!isset($condition['value']['value'])) { - $this->isConditionCorrect = false; - $this->conditionErrors[] = 'missing condition value'; - return; } $typeField = $condition['value']['property_meta']['type']; $operator = $condition['value']['operator']; $this->operator = $operator; - $value = $condition['value']['value']; if (!isset(self::getConditionMapping()[$typeField])) { $this->isConditionCorrect = false; $this->conditionErrors[] = 'configuration not found for condition type'; - return; } if (!isset(self::getConditionMapping()[$typeField]['comparators'][$operator])) { $this->isConditionCorrect = false; $this->conditionErrors[] = 'configuration not found for condition operator'; - return; } - $type = self::getConditionMapping()[$typeField]['comparators'][$operator]['expected_type'] ?? null; + $comparatorDef = self::getConditionMapping()[$typeField]['comparators'][$operator]; + $needsValue = !empty((array)$comparatorDef); - if (is_array($type)) { - $foundCorrectType = false; - foreach ($type as $subtype) { - if ($this->valueHasCorrectType($subtype, $value)) { - $foundCorrectType = true; + if ($needsValue && !isset($condition['value']['value'])) { + $this->isConditionCorrect = false; + $this->conditionErrors[] = 'missing condition value'; + return; + } + + if ($needsValue) { + $type = $comparatorDef['expected_type'] ?? null; + $value = $condition['value']['value']; + + if (is_array($type)) { + $foundCorrectType = false; + foreach ($type as $subtype) { + if ($this->valueHasCorrectType($subtype, $value)) { + $foundCorrectType = true; + } + } + if (!$foundCorrectType) { + $this->isConditionCorrect = false; + $this->conditionErrors[] = 'wrong type of condition value'; + } + } else { + if (!$this->valueHasCorrectType($type, $value)) { + $this->isConditionCorrect = false; + $this->conditionErrors[] = 'wrong type of condition value'; } - } - if (!$foundCorrectType) { - $this->isConditionCorrect = false; - } - } else { - if (!$this->valueHasCorrectType($type, $value)) { - $this->isConditionCorrect = false; - $this->conditionErrors[] = 'wrong type of condition value'; } } } diff --git a/api/tests/Feature/Forms/FormPropertyLogicTest.php b/api/tests/Feature/Forms/FormPropertyLogicTest.php index 01ed1615..04f7755d 100644 --- a/api/tests/Feature/Forms/FormPropertyLogicTest.php +++ b/api/tests/Feature/Forms/FormPropertyLogicTest.php @@ -199,3 +199,57 @@ it('can validate form logic rules for conditions', function () { $this->assertFalse($validatorObj->passes()); expect($validatorObj->errors()->messages()['properties.0.logic'][0])->toBe('The logic conditions for Name are not complete. Error detail(s): missing operator'); }); + +it('can validate form logic rules for operators without values', function () { + $rules = [ + 'properties.*.logic' => ['array', 'nullable', new FormPropertyLogicRule()], + ]; + + // Test checkbox is_checked without value + $data = [ + 'properties' => [ + [ + 'id' => 'checkbox1', + 'name' => 'Checkbox Field', + 'type' => 'checkbox', + 'logic' => [ + 'conditions' => [ + 'operatorIdentifier' => 'and', + 'children' => [ + [ + 'identifier' => 'test-id', + 'value' => [ + 'operator' => 'is_checked', + 'property_meta' => [ + 'id' => 'test-id', + 'type' => 'checkbox' + ] + ] + ] + ] + ], + 'actions' => ['show-block'] + ] + ] + ] + ]; + $validatorObj = $this->app['validator']->make($data, $rules); + $this->assertTrue($validatorObj->passes()); + + // Test checkbox is_checked with value (should still pass for backward compatibility) + $data['properties'][0]['logic']['conditions']['children'][0]['value']['value'] = true; + $validatorObj = $this->app['validator']->make($data, $rules); + $this->assertTrue($validatorObj->passes()); + + // Test checkbox is_not_checked without value + $data['properties'][0]['logic']['conditions']['children'][0]['value']['operator'] = 'is_not_checked'; + unset($data['properties'][0]['logic']['conditions']['children'][0]['value']['value']); + $validatorObj = $this->app['validator']->make($data, $rules); + $this->assertTrue($validatorObj->passes()); + + // Test checkbox with operator that doesn't exist + $data['properties'][0]['logic']['conditions']['children'][0]['value']['operator'] = 'invalid_operator'; + $validatorObj = $this->app['validator']->make($data, $rules); + $this->assertFalse($validatorObj->passes()); + expect($validatorObj->errors()->messages()['properties.0.logic'][0])->toBe('The logic conditions for Checkbox Field are not complete. Error detail(s): configuration not found for condition operator'); +}); diff --git a/client/components/open/forms/components/FormEditor.vue b/client/components/open/forms/components/FormEditor.vue index 11273a10..7ad0e10b 100644 --- a/client/components/open/forms/components/FormEditor.vue +++ b/client/components/open/forms/components/FormEditor.vue @@ -236,7 +236,6 @@ export default { saveForm() { // Apply defaults to the form const defaultedData = setFormDefaults(this.form.data()) - console.log('defaultedData', defaultedData) this.form.fill(defaultedData) this.form.properties = validatePropertiesLogic(this.form.properties) diff --git a/client/components/open/forms/components/form-components/FormErrorModal.vue b/client/components/open/forms/components/form-components/FormErrorModal.vue index bbcca1c7..bba8700e 100644 --- a/client/components/open/forms/components/form-components/FormErrorModal.vue +++ b/client/components/open/forms/components/form-components/FormErrorModal.vue @@ -4,8 +4,8 @@ @close="$emit('close')" >