From 853760484c790fa2e05b0b9b7da14109207d5695 Mon Sep 17 00:00:00 2001 From: Julien Nahum Date: Tue, 11 Feb 2025 15:05:27 +0100 Subject: [PATCH] Enhance form logic property resolver and validation UI - Refactor `shouldBeRequired()` method in FormLogicPropertyResolver for clearer logic and better handling of conditional requirements - Add comprehensive test cases for dynamic field requirement logic - Update CustomFieldValidation component with improved UI and guidance for validation setup - Improve error message and validation rule description in form validation interface --- .../Forms/FormLogicPropertyResolver.php | 26 +++--- .../Forms/FormLogicPropertyResolverTest.php | 87 +++++++++++++++++++ .../components/CustomFieldValidation.vue | 60 ++++++++----- 3 files changed, 142 insertions(+), 31 deletions(-) diff --git a/api/app/Service/Forms/FormLogicPropertyResolver.php b/api/app/Service/Forms/FormLogicPropertyResolver.php index 9319072c..88404ec7 100644 --- a/api/app/Service/Forms/FormLogicPropertyResolver.php +++ b/api/app/Service/Forms/FormLogicPropertyResolver.php @@ -29,22 +29,28 @@ class FormLogicPropertyResolver public function shouldBeRequired(): bool { - if (! isset($this->property['required'])) { - return false; - } + // Default required to false if not set + $isRequired = $this->property['required'] ?? false; if (! $this->logic) { - return $this->property['required']; + return $isRequired; } $conditionsMet = FormLogicConditionChecker::conditionsMet($this->logic['conditions'], $this->formData); - if ($conditionsMet && $this->property['required'] && count($this->logic['actions']) > 0 && (in_array('make-it-optional', $this->logic['actions']) || in_array('hide-block', $this->logic['actions']))) { - return false; - } elseif ($conditionsMet && ! $this->property['required'] && count($this->logic['actions']) > 0 && in_array('require-answer', $this->logic['actions'])) { - return true; - } else { - return $this->property['required']; + + // If conditions are met and we have actions + if ($conditionsMet && !empty($this->logic['actions'])) { + // If field is required but should be made optional + if ($isRequired && (in_array('make-it-optional', $this->logic['actions']) || in_array('hide-block', $this->logic['actions']))) { + return false; + } + // If field is not required but should be required + if (!$isRequired && in_array('require-answer', $this->logic['actions'])) { + return true; + } } + + return $isRequired; } public function shouldBeHidden(): bool diff --git a/api/tests/Unit/Service/Forms/FormLogicPropertyResolverTest.php b/api/tests/Unit/Service/Forms/FormLogicPropertyResolverTest.php index 5d7cdd7d..985a6408 100644 --- a/api/tests/Unit/Service/Forms/FormLogicPropertyResolverTest.php +++ b/api/tests/Unit/Service/Forms/FormLogicPropertyResolverTest.php @@ -107,4 +107,91 @@ it('can validate form logic property resolver', function ($property, $formData, ['93ea3198-353f-440b-8dc9-2ac9a7bee124' => [], '93ea3198-353f-440b-8dc9-2ac9a7bee222' => ['abc']], false, ], + [ + [ + 'id' => 'text_field', + 'name' => 'Required if checked', + 'type' => 'text', + 'hidden' => false, + 'logic' => [ + 'conditions' => [ + 'operatorIdentifier' => 'and', + 'children' => [ + [ + 'identifier' => 'checkbox', + 'value' => [ + 'operator' => 'is_checked', + 'property_meta' => [ + 'id' => 'checkbox_field', + 'type' => 'checkbox' + ], + 'value' => true + ] + ] + ] + ], + 'actions' => ['require-answer'] + ] + ], + ['checkbox_field' => true], + true + ], + [ + [ + 'id' => 'text_field', + 'name' => 'Required if checked', + 'type' => 'text', + 'hidden' => false, + 'logic' => [ + 'conditions' => [ + 'operatorIdentifier' => 'and', + 'children' => [ + [ + 'identifier' => 'checkbox', + 'value' => [ + 'operator' => 'is_checked', + 'property_meta' => [ + 'id' => 'checkbox_field', + 'type' => 'checkbox' + ], + 'value' => true + ] + ] + ] + ], + 'actions' => ['require-answer'] + ] + ], + ['checkbox_field' => false], + false + ], + [ + [ + 'id' => 'text_field', + 'name' => 'Required if checked', + 'type' => 'text', + 'hidden' => false, + 'logic' => [ + 'conditions' => [ + 'operatorIdentifier' => 'and', + 'children' => [ + [ + 'identifier' => 'checkbox', + 'value' => [ + 'operator' => 'is_checked', + 'property_meta' => [ + 'id' => 'checkbox_field', + 'type' => 'checkbox' + ], + 'value' => true + ] + ] + ] + ], + 'actions' => ['require-answer'] + ] + ], + ['checkbox_field' => null], + false + ] ]); diff --git a/client/components/open/forms/components/CustomFieldValidation.vue b/client/components/open/forms/components/CustomFieldValidation.vue index 4d70d5c7..82c01789 100644 --- a/client/components/open/forms/components/CustomFieldValidation.vue +++ b/client/components/open/forms/components/CustomFieldValidation.vue @@ -1,33 +1,51 @@