From f6e09f09e8f901794959bc5fae1a649f22d5bf0d Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Sat, 25 Jul 2020 09:55:11 +0200 Subject: [PATCH] fix(targetticket): last valid category ignored visibility state Signed-off-by: Thierry Bugier --- inc/fields.class.php | 3 +- inc/fields/dropdownfield.class.php | 6 + inc/form.class.php | 2 +- inc/targetbase.class.php | 67 +++-- .../PluginFormcreatorTargetTicket.php | 271 ++++++++++++------ 5 files changed, 225 insertions(+), 124 deletions(-) diff --git a/inc/fields.class.php b/inc/fields.class.php index edc1ae807..0b990d4e9 100644 --- a/inc/fields.class.php +++ b/inc/fields.class.php @@ -112,7 +112,8 @@ public static function getNames() { } /** - * Reset the cache of visibility of hide-able items + * Reset cache of evaluated visibility + * used for unit tests * * @return void */ diff --git a/inc/fields/dropdownfield.class.php b/inc/fields/dropdownfield.class.php index 0b6733988..bba93a641 100644 --- a/inc/fields/dropdownfield.class.php +++ b/inc/fields/dropdownfield.class.php @@ -385,9 +385,15 @@ public function prepareQuestionInputForSave($input) { if (is_a($input['dropdown_values'], "CommonTreeDropdown", true)) { // Specific param for ITILCategory if ($input['dropdown_values'] == ITILCategory::class) { + if (!isset($input['show_ticket_categories'])) { + $input['show_ticket_categories'] = 'all'; + } $input['values']['show_ticket_categories'] = $input['show_ticket_categories']; } + if (!isset($input['show_ticket_categories_depth'])) { + $input['show_ticket_categories_depth'] = 0; + } if ($input['show_ticket_categories_depth'] != (int) $input['show_ticket_categories_depth']) { $input['values']['show_ticket_categories_depth'] = 0; } else { diff --git a/inc/form.class.php b/inc/form.class.php index 47f68f12f..0978ebd1e 100644 --- a/inc/form.class.php +++ b/inc/form.class.php @@ -2171,7 +2171,7 @@ public function getFromDBByQuestion(PluginFormcreatorQuestion $question) { /** * Get an array of instances of all fields for the form * - * @return array + * @return PluginFormcreatorFields[] */ public function getFields() { $fields = []; diff --git a/inc/targetbase.class.php b/inc/targetbase.class.php index dea97edc0..05390a404 100644 --- a/inc/targetbase.class.php +++ b/inc/targetbase.class.php @@ -377,10 +377,10 @@ protected function setTargetEntity($data, PluginFormcreatorFormAnswer $formanswe return $data; } - protected function setTargetCategory($data, $formanswer) { + protected function setTargetCategory($data, PluginFormcreatorFormAnswer $formanswer) { global $DB; - $category = null; + $category = 0; switch ($this->fields['category_rule']) { case self::CATEGORY_RULE_ANSWER: @@ -398,54 +398,53 @@ protected function setTargetCategory($data, $formanswer) { $category = $this->fields['category_question']; break; case self::CATEGORY_RULE_LAST_ANSWER: - $form_id = $formanswer->fields['id']; - - // Get all answers for dropdown questions of this form, ordered - // from last to first displayed - $answers = $DB->request([ - 'SELECT' => ['answer.answer', 'question.values'], - 'FROM' => PluginFormcreatorAnswer::getTable() . ' AS answer', - 'JOIN' => [ - PluginFormcreatorQuestion::getTable() . ' AS question' => [ - 'ON' => [ - 'answer' => 'plugin_formcreator_questions_id', - 'question' => 'id', - ] - ] - ], - 'WHERE' => [ - 'answer.plugin_formcreator_formanswers_id' => $form_id, - 'question.fieldtype' => "dropdown", - ], - 'ORDER' => [ - 'row DESC', - 'col DESC', - ] - ]); + $questionFields = $formanswer->getForm()->getFields(); + $answers_values = $formanswer->getAnswers($formanswer->getID()); + foreach ($questionFields as $id => $question) { + $questionFields[$id]->deserializeValue($answers_values['formcreator_field_' . $id]); + } + + // filter questions; keep DropdownFields only + $filteredFields = array_filter($questionFields, function($item) { + return get_class($item) === PluginFormcreatorDropdownField::class; + }); + + // Sort question in reverse order + uasort($filteredFields, function($a, $b) { + $orderA = $a->getQuestion()->fields['order']; + $orderB = $b->getQuestion()->fields['order']; + if ($orderA == $orderB) { + return 0; + } + return ($orderA > $orderB) ? -1 : 1; + }); - foreach ($answers as $answer) { + foreach ($filteredFields as $questionField) { // Decode dropdown settings - $itemtype = \PluginFormcreatorDropdownField::getSubItemtypeForValues($answer['values']); + $itemtype = \PluginFormcreatorDropdownField::getSubItemtypeForValues($questionField->getQuestion()->fields['values']); // Skip if not a dropdown on categories - if ($itemtype !== "ITILCategory") { + if ($itemtype !== ITILCategory::class) { + continue; + } + + // Skip if question is invisible + if (!PluginFormcreatorFields::isVisible($questionField->getQuestion(), $questionFields)) { continue; } // Skip if question was not answered - if (empty($answer['answer'])) { + if (empty($questionField->getValueForDesign())) { continue; } // Found a valid answer, stop here - $category = $answer['answer']; + $category = $questionField->getValueForDesign(); break; } break; } - if ($category !== null) { - $data['itilcategories_id'] = $category; - } + $data['itilcategories_id'] = $category; return $data; } diff --git a/tests/suite-unit/PluginFormcreatorTargetTicket.php b/tests/suite-unit/PluginFormcreatorTargetTicket.php index cdc753ccc..cc62ec8ce 100644 --- a/tests/suite-unit/PluginFormcreatorTargetTicket.php +++ b/tests/suite-unit/PluginFormcreatorTargetTicket.php @@ -811,52 +811,147 @@ function() use($linker, $input, $form) { $this->integer((int) $targetTicketId)->isNotEqualTo($targetTicketId2); } - /* - public function testSetTargetCategory() { + public function providerSetTargetCategory() { + $category1 = new \ITILCategory(); + $category1Id = $category1->import([ + 'name' => 'category 1', + 'entities_id' => 0, + ]); + $category2 = new \ITILCategory(); + $category2Id = $category2->import([ + 'name' => 'category 2', + 'entities_id' => 0, + ]); - $instance = new PluginFormcreatorTargetTicketDummy(); - $question = $this->getQuestion([ - 'fieldtype' => 'dropdown', - 'values' => json_encode([ - 'itemtype' => 'ITILCategory', - 'show_ticket_categories' =>'both', - 'show_ticket_categories_depth' => '0', - 'show_ticket_categories_root' => '0', - ]), + // Crate a task category and ensure its ID is not the + // same as the ticket categories created above + $taskCategoryId = 0; + do { + $taskCategory = new \TaskCategory(); + $taskCategoryId = $taskCategory->import([ + 'name' => $this->getUniqueString(), + 'entities_id' => 0, + ]); + } while($taskCategoryId == $category1Id || $taskCategoryId == $category2Id); + + $question1 = $this->getQuestion([ + 'name' => 'request type', + 'fieldtype' => 'requesttype', ]); - $form = new \PluginFormcreatorForm(); - $form->getByQuestionId($question->getID()); - $fields = $form->getFields(); - $instance->add([ - 'name' => 'foo', - 'plugin_formcreator_forms_id' => $form->getID(), - 'category_rule' => \PluginFormcreatorTargetTicket::CATEGORY_RULE_ANSWER, - 'category_question' => $question->getID(), + $this->boolean($question1->isNewItem())->isFalse(); + $section = new \PluginFormcreatorSection(); + $section->getFromDB($question1->fields['plugin_formcreator_sections_id']); + $this->boolean($section->isNewItem())->isFalse(); + $question2 = $this->getQuestion([ + 'plugin_formcreator_sections_id' => $section->getID(), + 'name' => 'request category', + 'fieldtype' => 'dropdown', + 'dropdown_values' => \ITILCategory::class, + 'show_rule' => \PluginFormcreatorCondition::SHOW_RULE_HIDDEN, + '_conditions' => [ + 'show_logic' => [\PluginFormcreatorCondition::SHOW_LOGIC_AND], + 'plugin_formcreator_questions_id' => [$question1->getID()], + 'show_condition' => [\PluginFormcreatorCondition::SHOW_CONDITION_EQ], + 'show_value' => ['Incident'], + ] + ]); + $question3 = $this->getQuestion([ + 'plugin_formcreator_sections_id' => $section->getID(), + 'name' => 'incident category', + 'fieldtype' => 'dropdown', + 'dropdown_values' => \ITILCategory::class, + 'show_rule' => \PluginFormcreatorCondition::SHOW_RULE_HIDDEN, + '_conditions' => [ + 'show_logic' => [\PluginFormcreatorCondition::SHOW_LOGIC_AND], + 'plugin_formcreator_questions_id' => [$question1->getID()], + 'show_condition' => [\PluginFormcreatorCondition::SHOW_CONDITION_EQ], + 'show_value' => ['Request'], + ] + ]); + $question4 = $this->getQuestion([ + 'plugin_formcreator_sections_id' => $section->getID(), + 'name' => 'other category', + 'fieldtype' => 'dropdown', + 'dropdown_values' => \TaskCategory::class, + '_conditions' => [ + 'show_logic' => [], + 'plugin_formcreator_questions_id' => [], + 'show_condition' => [], + 'show_value' => [], + ] ]); - $input = [ - 'formcreator_field_' . $question->getID() => '42', - ]; - foreach ($fields as $id => $field) { - $field->parseAnswerValues($input); - } - $formAnswer = new \PluginFormcreatorFormAnswer(); - // // $this->disableDebug(); - $formAnswer->saveAnswers( - $form, - $input, - $fields - ); - // // $this->restoreDebug(); - $data = []; - $expected = [ - 'itilcategories_id' => '42', + $formanswer1 = new \PluginFormcreatorFormAnswer(); + $formanswer1->add([ + 'plugin_formcreator_forms_id' => $section->fields['plugin_formcreator_forms_id'], + 'formcreator_field_' . $question1->getID() => (string) \Ticket::INCIDENT_TYPE, + 'formcreator_field_' . $question2->getID() => (string) $category1Id, + 'formcreator_field_' . $question3->getID() => (string) $category2Id, + 'formcreator_field_' . $question4->getID() => (string) $taskCategoryId, + ]); + + $formanswer2 = new \PluginFormcreatorFormAnswer(); + $formanswer2->add([ + 'plugin_formcreator_forms_id' => $section->fields['plugin_formcreator_forms_id'], + 'formcreator_field_' . $question1->getID() => (string) \Ticket::DEMAND_TYPE, + 'formcreator_field_' . $question2->getID() => (string) $category1Id, + 'formcreator_field_' . $question3->getID() => (string) $category2Id, + 'formcreator_field_' . $question4->getID() => (string) $taskCategoryId, + ]); + + $formanswer3 = new \PluginFormcreatorFormAnswer(); + $formanswer3->add([ + 'plugin_formcreator_forms_id' => $section->fields['plugin_formcreator_forms_id'], + 'formcreator_field_' . $question1->getID() => (string) \Ticket::INCIDENT_TYPE, + 'formcreator_field_' . $question2->getID() => (string) $category1Id, + 'formcreator_field_' . $question3->getID() => (string) 0, + 'formcreator_field_' . $question4->getID() => (string) $taskCategoryId, + ]); + + $instance1 = $this->newTestedInstance(); + $instance1->add([ + 'name' => 'target ticket', + 'target_name' => 'target ticket', + 'plugin_formcreator_forms_id' => $formanswer1->getForm()->getID(), + 'category_rule' => \PluginFormcreatorTargetTicket::CATEGORY_RULE_LAST_ANSWER, + ]); + + return [ + // Check visibility is taken into acount + // [ + // 'instance' => $instance1, + // 'formanswer' => $formanswer1, + // 'expected' => $category1Id, + // ], + // Check not ticketcategory dropdown is ignored + // [ + // 'instance' => $instance1, + // 'formanswer' => $formanswer2, + // 'expected' => $category2Id, + // ], + // Check zero value is ignored + [ + 'instance' => $instance1, + 'formanswer' => $formanswer3, + 'expected' => $category1Id, + ] ]; + } - $output = $instance->publicSetTargetCategory($data, $formAnswer); - $this->integer((int) $output['itilcategories_id'])->isEqualTo($expected['itilcategories_id']); + /** + * @dataProvider providerSetTargetCategory + */ + public function testSetTargetCategory($instance, $formanswer, $expected) { + + // Substitute a dummy class to access protected / private methods + $dummyItemtype = 'GlpiPlugin\Formcreator\Tests\\' . $this->getTestedClassName() . 'Dummy'; + $dummyInstance = new $dummyItemtype(); + $dummyInstance->fields = $instance->fields; + + \PluginFormcreatorFields::resetVisibilityCache(); + $output = $dummyInstance->publicSetTargetCategory([], $formanswer); + $this->integer((int) $output['itilcategories_id'])->isEqualTo($expected); } - */ public function testSetTargetAssociatedItem() { global $CFG_GLPI; @@ -963,55 +1058,55 @@ public function testSetTargetAssociatedItemLastAnswer( $this->array($res)->isEqualTo($results); } - /** - * @dataProvider providerSetTargetAssociatedCategoryLastAnswer - */ - public function testSetTargetCategoryLastAnswer( - array $answers, - array $results - ) { - global $DB; - - $lastAnswer = \PluginFormcreatorTargetBase::CATEGORY_RULE_LAST_ANSWER; - - // Prepare instance - $instance = new PluginFormcreatorTargetTicketDummy(); - $instance->fields = ['category_rule' => $lastAnswer]; - - // Prepare args - $data = []; - $formAnswer = new \PluginFormcreatorFormAnswer(); - $formAnswer->fields = ['id' => 1]; - - // Mock call to $DB - $DB = new \mock\DB(); - - // $db->request() - $answerTable = \PluginFormcreatorAnswer::getTable() . ' AS answer'; - - $this->calling($DB)->request = function ( - $tableorsql, - $crit = "", - $debug = false - ) use ($DB, $answers, $answerTable) { - - // $DB is trying to load the answers for the form - if (isset($tableorsql['FROM']) && $tableorsql['FROM'] == $answerTable) { - return new \ArrayIterator($answers); - } - - // Keep normal execution for others requests - $iterator = new \DBmysqlIterator($DB); - $iterator->execute($tableorsql, $crit, $debug); - return $iterator; - }; - - // Execute the test - $res = $instance->publicSetTargetCategory($data, $formAnswer); - - // Assert results - $this->array($res)->isEqualTo($results); - } + // /** + // * @dataProvider providerSetTargetAssociatedCategoryLastAnswer + // */ + // public function testSetTargetCategoryLastAnswer( + // array $answers, + // array $results + // ) { + // global $DB; + + // $lastAnswer = \PluginFormcreatorTargetBase::CATEGORY_RULE_LAST_ANSWER; + + // // Prepare instance + // $instance = new PluginFormcreatorTargetTicketDummy(); + // $instance->fields = ['category_rule' => $lastAnswer]; + + // // Prepare args + // $data = []; + // $formAnswer = new PluginFormcreatorFormAnswer(); + // $formAnswer->fields = ['id' => 1]; + + // // Mock call to $DB + // $DB = new \mock\DB(); + + // // $db->request() + // $answerTable = \PluginFormcreatorAnswer::getTable() . ' AS answer'; + + // $this->calling($DB)->request = function ( + // $tableorsql, + // $crit = "", + // $debug = false + // ) use ($DB, $answers, $answerTable) { + + // // $DB is trying to load the answers for the form + // if (isset($tableorsql['FROM']) && $tableorsql['FROM'] == $answerTable) { + // return new \ArrayIterator($answers); + // } + + // // Keep normal execution for others requests + // $iterator = new \DBmysqlIterator($DB); + // $iterator->execute($tableorsql, $crit, $debug); + // return $iterator; + // }; + + // // Execute the test + // $res = $instance->publicSetTargetCategory($data, $formAnswer); + + // // Assert results + // $this->array($res)->isEqualTo($results); + // } public function testIsEntityAssign() { $instance = $this->newTestedInstance();