diff --git a/src/Glpi/Form/Comment.php b/src/Glpi/Form/Comment.php index baf2834a3f9..1199b467a07 100644 --- a/src/Glpi/Form/Comment.php +++ b/src/Glpi/Form/Comment.php @@ -169,6 +169,8 @@ private function prepareInput(array $input): array unset($input['_conditions']); } + $input = $this->removeSavedConditionsIfAlwaysVisible($input); + return $input; } diff --git a/src/Glpi/Form/Condition/ConditionableCreationInterface.php b/src/Glpi/Form/Condition/ConditionableCreationInterface.php index edf515fb570..6d500615464 100644 --- a/src/Glpi/Form/Condition/ConditionableCreationInterface.php +++ b/src/Glpi/Form/Condition/ConditionableCreationInterface.php @@ -37,4 +37,7 @@ interface ConditionableCreationInterface extends ConditionableInterface { public function getConfiguredCreationStrategy(): CreationStrategy; + + // TODO: uncomment on main to prevent BC breaks + // protected function removeSavedConditionsIfAlwaysCreated(array $input): array; } diff --git a/src/Glpi/Form/Condition/ConditionableCreationTrait.php b/src/Glpi/Form/Condition/ConditionableCreationTrait.php index 395dcbee889..5cae360c05b 100644 --- a/src/Glpi/Form/Condition/ConditionableCreationTrait.php +++ b/src/Glpi/Form/Condition/ConditionableCreationTrait.php @@ -34,6 +34,8 @@ namespace Glpi\Form\Condition; +use function Safe\json_encode; + trait ConditionableCreationTrait { use ConditionableTrait; @@ -44,4 +46,19 @@ public function getConfiguredCreationStrategy(): CreationStrategy $strategy = CreationStrategy::tryFrom($strategy_value); return $strategy ?? CreationStrategy::ALWAYS_CREATED; } + + protected function removeSavedConditionsIfAlwaysCreated(array $input): array + { + $strategy_field = 'creation_strategy'; + $condition_field = $this->getConditionsFieldName(); + + if ( + isset($input[$strategy_field]) + && $input[$strategy_field] == CreationStrategy::ALWAYS_CREATED->value + ) { + $input[$condition_field] = json_encode([]); + } + + return $input; + } } diff --git a/src/Glpi/Form/Condition/ConditionableValidationTrait.php b/src/Glpi/Form/Condition/ConditionableValidationTrait.php index 7298067e4c5..31cdd083905 100644 --- a/src/Glpi/Form/Condition/ConditionableValidationTrait.php +++ b/src/Glpi/Form/Condition/ConditionableValidationTrait.php @@ -34,6 +34,8 @@ namespace Glpi\Form\Condition; +use function Safe\json_encode; + trait ConditionableValidationTrait { use ConditionableTrait { @@ -76,4 +78,19 @@ public function getConfiguredValidationStrategy(): ValidationStrategy $strategy = ValidationStrategy::tryFrom($strategy_value); return $strategy ?? ValidationStrategy::NO_VALIDATION; } + + protected function removeSavedConditionsIfNoValidation(array $input): array + { + $strategy_field = $this->getValidationStrategyFieldName(); + $condition_field = $this->getValidationConditionsFieldName(); + + if ( + isset($input[$strategy_field]) + && $input[$strategy_field] == ValidationStrategy::NO_VALIDATION->value + ) { + $input[$condition_field] = json_encode([]); + } + + return $input; + } } diff --git a/src/Glpi/Form/Condition/ConditionableVisibilityInterface.php b/src/Glpi/Form/Condition/ConditionableVisibilityInterface.php index 61b11269ac2..4c279b625e7 100644 --- a/src/Glpi/Form/Condition/ConditionableVisibilityInterface.php +++ b/src/Glpi/Form/Condition/ConditionableVisibilityInterface.php @@ -49,4 +49,7 @@ public function getConfiguredVisibilityStrategy(): VisibilityStrategy; * @return string */ public function getUUID(): string; + + // TODO: uncomment on main to prevent BC breaks + // protected function removeSavedConditionsIfAlwaysVisible(array $input): array; } diff --git a/src/Glpi/Form/Condition/ConditionableVisibilityTrait.php b/src/Glpi/Form/Condition/ConditionableVisibilityTrait.php index b769c406b2d..615d9f6c47d 100644 --- a/src/Glpi/Form/Condition/ConditionableVisibilityTrait.php +++ b/src/Glpi/Form/Condition/ConditionableVisibilityTrait.php @@ -34,6 +34,8 @@ namespace Glpi\Form\Condition; +use function Safe\json_encode; + trait ConditionableVisibilityTrait { use ConditionableTrait; @@ -56,4 +58,19 @@ public function getConfiguredVisibilityStrategy(): VisibilityStrategy $strategy = VisibilityStrategy::tryFrom($strategy_value); return $strategy ?? VisibilityStrategy::ALWAYS_VISIBLE; } + + protected function removeSavedConditionsIfAlwaysVisible(array $input): array + { + $visibility_field = $this->getVisibilityStrategyFieldName(); + $condition_field = $this->getConditionsFieldName(); + + if ( + isset($input[$visibility_field]) + && $input[$visibility_field] == VisibilityStrategy::ALWAYS_VISIBLE->value + ) { + $input[$condition_field] = json_encode([]); + } + + return $input; + } } diff --git a/src/Glpi/Form/Destination/FormDestination.php b/src/Glpi/Form/Destination/FormDestination.php index ed8348e2666..8856b19a40b 100644 --- a/src/Glpi/Form/Destination/FormDestination.php +++ b/src/Glpi/Form/Destination/FormDestination.php @@ -284,6 +284,8 @@ public function prepareInput($input): array unset($input['_conditions']); } + $input = $this->removeSavedConditionsIfAlwaysCreated($input); + return $input; } diff --git a/src/Glpi/Form/Form.php b/src/Glpi/Form/Form.php index 900eea488a9..a456bb45191 100644 --- a/src/Glpi/Form/Form.php +++ b/src/Glpi/Form/Form.php @@ -374,6 +374,8 @@ private function prepareInput(array $input): array unset($input['_submit_button_conditions']); } + $input = $this->removeSavedConditionsIfAlwaysVisible($input); + return $input; } diff --git a/src/Glpi/Form/Question.php b/src/Glpi/Form/Question.php index fd243dd3989..8d6371d73bf 100644 --- a/src/Glpi/Form/Question.php +++ b/src/Glpi/Form/Question.php @@ -401,6 +401,9 @@ private function prepareInput(array $input): array } } + $input = $this->removeSavedConditionsIfAlwaysVisible($input); + $input = $this->removeSavedConditionsIfNoValidation($input); + return $input; } diff --git a/src/Glpi/Form/Section.php b/src/Glpi/Form/Section.php index 3868d2a6ce0..58c533f76bb 100644 --- a/src/Glpi/Form/Section.php +++ b/src/Glpi/Form/Section.php @@ -144,6 +144,8 @@ private function prepareInput(array $input): array unset($input['_conditions']); } + $input = $this->removeSavedConditionsIfAlwaysVisible($input); + return $input; } diff --git a/tests/functional/Glpi/Form/CommentTest.php b/tests/functional/Glpi/Form/CommentTest.php new file mode 100644 index 00000000000..b95e84f5304 --- /dev/null +++ b/tests/functional/Glpi/Form/CommentTest.php @@ -0,0 +1,77 @@ +. + * + * --------------------------------------------------------------------- + */ + +namespace tests\units\Glpi\Form; + +use DbTestCase; +use Glpi\Form\Comment; +use Glpi\Form\Condition\LogicOperator; +use Glpi\Form\Condition\Type; +use Glpi\Form\Condition\ValueOperator; +use Glpi\Form\Condition\VisibilityStrategy; +use Glpi\Form\QuestionType\QuestionTypeShortText; +use Glpi\Tests\FormBuilder; +use Glpi\Tests\FormTesterTrait; + +final class CommentTest extends DbTestCase +{ + use FormTesterTrait; + + public function testConditionsDataAreCleanedWhenStrategyIsReset(): void + { + // Arrange: create a form with visibility conditions on a comment + $builder = new FormBuilder(); + $builder->addQuestion("My question", QuestionTypeShortText::class); + $builder->addComment("My comment"); + $builder->setCommentVisibility("My comment", VisibilityStrategy::VISIBLE_IF, [ + [ + 'logic_operator' => LogicOperator::AND, + 'item_name' => "My question", + 'item_type' => Type::QUESTION, + 'value_operator' => ValueOperator::EQUALS, + 'value' => "Yes", + ], + ]); + $form = $this->createForm($builder); + + // Act: reset the comment's visibility strategy + $comment_id = $this->getCommentId($form, "My comment"); + $comment = $this->updateItem(Comment::class, $comment_id, [ + 'visibility_strategy' => VisibilityStrategy::ALWAYS_VISIBLE->value, + ]); + + // Assert: the conditions should be deleted + $this->assertEmpty($comment->getConfiguredConditionsData()); + } +} diff --git a/tests/functional/Glpi/Form/Destination/FormDestinationTest.php b/tests/functional/Glpi/Form/Destination/FormDestinationTest.php index 30bce6286f7..70ddd4be79e 100644 --- a/tests/functional/Glpi/Form/Destination/FormDestinationTest.php +++ b/tests/functional/Glpi/Form/Destination/FormDestinationTest.php @@ -37,6 +37,10 @@ use CommonGLPI; use DBmysql; use DbTestCase; +use Glpi\Form\Condition\CreationStrategy; +use Glpi\Form\Condition\LogicOperator; +use Glpi\Form\Condition\Type; +use Glpi\Form\Condition\ValueOperator; use Glpi\Form\Destination\FormDestination; use Glpi\Form\Destination\FormDestinationTicket; use Glpi\Form\Form; @@ -153,6 +157,32 @@ public function testWarningsAreRendereredInTabContent() ); } + public function testConditionsDataAreCleanedWhenStrategyIsReset(): void + { + // Arrange: create a form with creation conditions on a destination + $builder = new FormBuilder(); + $builder->addQuestion("My question", QuestionTypeShortText::class); + $builder->setDestinationCondition("Ticket", CreationStrategy::CREATED_IF, [ + [ + 'logic_operator' => LogicOperator::AND, + 'item_name' => "My question", + 'item_type' => Type::QUESTION, + 'value_operator' => ValueOperator::EQUALS, + 'value' => "Yes", + ], + ]); + $form = $this->createForm($builder); + + // Act: reset the destiantion's creation strategy + $destination_id = $this->getDestinationId($form, "Ticket"); + $destination = $this->updateItem(FormDestination::class, $destination_id, [ + 'creation_strategy' => CreationStrategy::ALWAYS_CREATED->value, + ]); + + // Assert: the conditions should be deleted + $this->assertEmpty($destination->getConfiguredConditionsData()); + } + private function createAndGetFormWithFourDestinations(): Form { $builder = new FormBuilder(); diff --git a/tests/functional/Glpi/Form/FormTest.php b/tests/functional/Glpi/Form/FormTest.php index 681bd426a27..693ab01e14f 100644 --- a/tests/functional/Glpi/Form/FormTest.php +++ b/tests/functional/Glpi/Form/FormTest.php @@ -43,6 +43,10 @@ use Glpi\Form\AccessControl\FormAccessControl; use Glpi\Form\AnswersHandler\AnswersHandler; use Glpi\Form\Comment; +use Glpi\Form\Condition\LogicOperator; +use Glpi\Form\Condition\Type; +use Glpi\Form\Condition\ValueOperator; +use Glpi\Form\Condition\VisibilityStrategy; use Glpi\Form\Destination\FormDestination; use Glpi\Form\Destination\FormDestinationChange; use Glpi\Form\Destination\FormDestinationProblem; @@ -811,4 +815,29 @@ public function testDefinedTabs( // Assert: the tabs should match the expected data $this->assertEquals($expected_tabs, $tabs); } + + public function testSubmitConditionsDataAreCleanedWhenStrategyIsReset(): void + { + // Arrange: create a form with a condition on its submit button + $builder = new FormBuilder(); + $builder->addQuestion("My question", QuestionTypeShortText::class); + $builder->setSubmitButtonVisibility(VisibilityStrategy::VISIBLE_IF, [ + [ + 'logic_operator' => LogicOperator::AND, + 'item_name' => "My question", + 'item_type' => Type::QUESTION, + 'value_operator' => ValueOperator::EQUALS, + 'value' => "Yes", + ], + ]); + $form = $this->createForm($builder); + + // Act: reset the submit button's visibility strategy + $form = $this->updateItem(Form::class, $form->getID(), [ + 'submit_button_visibility_strategy' => VisibilityStrategy::ALWAYS_VISIBLE->value, + ]); + + // Assert: the conditions should be deleted + $this->assertEmpty($form->getConfiguredConditionsData()); + } } diff --git a/tests/functional/Glpi/Form/QuestionTest.php b/tests/functional/Glpi/Form/QuestionTest.php index 2eecee0df67..e22a5413cbe 100644 --- a/tests/functional/Glpi/Form/QuestionTest.php +++ b/tests/functional/Glpi/Form/QuestionTest.php @@ -36,16 +36,25 @@ use Computer; use DbTestCase; +use Glpi\Form\Condition\LogicOperator; +use Glpi\Form\Condition\Type; +use Glpi\Form\Condition\ValidationStrategy; +use Glpi\Form\Condition\ValueOperator; +use Glpi\Form\Condition\VisibilityStrategy; use Glpi\Form\Question; use Glpi\Form\QuestionType\AbstractQuestionTypeShortAnswer; use Glpi\Form\QuestionType\QuestionTypeEmail; use Glpi\Form\QuestionType\QuestionTypeLongText; use Glpi\Form\QuestionType\QuestionTypeNumber; use Glpi\Form\QuestionType\QuestionTypeShortText; +use Glpi\Tests\FormBuilder; +use Glpi\Tests\FormTesterTrait; use PHPUnit\Framework\Attributes\DataProvider; class QuestionTest extends DbTestCase { + use FormTesterTrait; + public static function getQuestionTypeProvider(): iterable { // First set of tests: valid values @@ -99,4 +108,66 @@ public function testGetQuestionType(Question $question, $expected): void $type = $question->getQuestionType(); $this->assertEquals($expected, $type); } + + public function testVisibilityConditionsDataAreCleanedWhenStrategyIsReset(): void + { + // Arrange: create a form with visibility conditions on a question + $builder = new FormBuilder(); + $builder->addQuestion("My question", QuestionTypeShortText::class); + $builder->addQuestion("My other question", QuestionTypeShortText::class); + $builder->setQuestionVisibility( + "My other question", + VisibilityStrategy::VISIBLE_IF, + [ + [ + 'logic_operator' => LogicOperator::AND, + 'item_name' => "My question", + 'item_type' => Type::QUESTION, + 'value_operator' => ValueOperator::EQUALS, + 'value' => "Yes", + ], + ] + ); + $form = $this->createForm($builder); + + // Act: reset the question's visibility strategy + $question_id = $this->getQuestionId($form, "My other question"); + $question = $this->updateItem(Question::class, $question_id, [ + 'visibility_strategy' => VisibilityStrategy::ALWAYS_VISIBLE->value, + ]); + + // Assert: the conditions should be deleted + $this->assertEmpty($question->getConfiguredConditionsData()); + } + + public function testValidationConditionsDataAreCleanedWhenStrategyIsReset(): void + { + // Arrange: create a form with visibility conditions on a question + $builder = new FormBuilder(); + $builder->addQuestion("My question", QuestionTypeShortText::class); + $builder->addQuestion("My other question", QuestionTypeShortText::class); + $builder->setQuestionValidation( + "My other question", + ValidationStrategy::VALID_IF, + [ + [ + 'logic_operator' => LogicOperator::AND, + 'item_name' => "My question", + 'item_type' => Type::QUESTION, + 'value_operator' => ValueOperator::EQUALS, + 'value' => "Yes", + ], + ] + ); + $form = $this->createForm($builder); + + // Act: reset the question's validation strategy + $question_id = $this->getQuestionId($form, "My other question"); + $question = $this->updateItem(Question::class, $question_id, [ + 'validation_strategy' => ValidationStrategy::NO_VALIDATION->value, + ]); + + // Assert: the conditions should be deleted + $this->assertEmpty($question->getConfiguredValidationConditionsData()); + } } diff --git a/tests/functional/Glpi/Form/SectionTest.php b/tests/functional/Glpi/Form/SectionTest.php index 819cc068b55..746dd9ea3df 100644 --- a/tests/functional/Glpi/Form/SectionTest.php +++ b/tests/functional/Glpi/Form/SectionTest.php @@ -35,6 +35,10 @@ namespace tests\units\Glpi\Form; use DbTestCase; +use Glpi\Form\Condition\LogicOperator; +use Glpi\Form\Condition\Type; +use Glpi\Form\Condition\ValueOperator; +use Glpi\Form\Condition\VisibilityStrategy; use Glpi\Form\Question; use Glpi\Form\QuestionType\QuestionTypeShortText; use Glpi\Form\Section; @@ -114,6 +118,34 @@ public function testGetQuestionsForSectionWithInvalidQuestions(): void $this->checkGetQuestions($section, ['Valid question type']); } + public function testConditionsDataAreCleanedWhenStrategyIsReset(): void + { + // Arrange: create a form with visibility conditions on a section + $builder = new FormBuilder(); + $builder->addSection("Section 1"); + $builder->addQuestion("My question", QuestionTypeShortText::class); + $builder->addSection("Section 2"); + $builder->setSectionVisibility("Section 2", VisibilityStrategy::VISIBLE_IF, [ + [ + 'logic_operator' => LogicOperator::AND, + 'item_name' => "My question", + 'item_type' => Type::QUESTION, + 'value_operator' => ValueOperator::EQUALS, + 'value' => "Yes", + ], + ]); + $form = $this->createForm($builder); + + // Act: reset the section's visibility strategy + $section_id = $this->getSectionId($form, "Section 2"); + $section = $this->updateItem(Section::class, $section_id, [ + 'visibility_strategy' => VisibilityStrategy::ALWAYS_VISIBLE->value, + ]); + + // Assert: the conditions should be deleted + $this->assertEmpty($section->getConfiguredConditionsData()); + } + private function checkGetQuestions( Section $section, array $expected_questions_names