Skip to content

Commit

Permalink
refactor: End user input name handling to new class
Browse files Browse the repository at this point in the history
  • Loading branch information
ccailly committed Apr 26, 2024
1 parent de5b972 commit 79d4121
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 18 deletions.
16 changes: 2 additions & 14 deletions ajax/form/answer.php
Expand Up @@ -34,6 +34,7 @@
*/

use Glpi\Form\AnswersHandler\AnswersHandler;
use Glpi\Form\EndUserInputNameProvider;
use Glpi\Form\Form;
use Glpi\Form\Question;
use Glpi\Http\Response;
Expand All @@ -59,20 +60,7 @@
}

// Validate the 'answers' parameter by filtering and reindexing the $_POST array.
// It first filters the keys that match a specific regex pattern,
// then reindexes the array by transforming the keys to integers.
$answers = array_reduce(
array_keys($_POST),
function ($carry, $key) {
if (preg_match(Question::END_USER_INPUT_NAME_REGEX, $key)) {
$question_id = (int) preg_replace(Question::END_USER_INPUT_NAME_REGEX, '$1', $key);
$carry[$question_id] = $_POST[$key];
}
return $carry;
},
[]
);

$answers = EndUserInputNameProvider::getAnswers();
if (empty($answers)) {
Response::sendError(400, __('Invalid answers'));
}
Expand Down
108 changes: 108 additions & 0 deletions src/Form/EndUserInputNameProvider.php
@@ -0,0 +1,108 @@
<?php

/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2024 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/

namespace Glpi\Form;

/**
* Helpdesk form
*/
final class EndUserInputNameProvider
{
public const END_USER_INPUT_NAME = 'answers_%d';
public const END_USER_INPUT_NAME_REGEX = '/^_?answers_(\d+)$/';

/**
* Get the end user input name for a given question
*
* @param Question $question
* @return string
*/
public static function getEndUserInputName(Question $question): string
{
return sprintf(static::END_USER_INPUT_NAME, $question->getID());
}

/**
* Get the answers submitted by the end user
* The answers are indexed by question ID
*
* @return array
*/
public static function getAnswers(): array
{
$filteredAnswers = self::filterAnswers($_POST);
$reindexedAnswers = self::reindexAnswers($filteredAnswers);

return $reindexedAnswers;
}

/**
* Filter the answers submitted by the end user
* Only the answers that match the end user input name pattern are kept
*
* @param array $answers
* @return array
*/
private static function filterAnswers(array $answers): array
{
return array_filter(
$answers,
function ($key) {
return preg_match(self::END_USER_INPUT_NAME_REGEX, $key);
},
ARRAY_FILTER_USE_KEY
);
}

/**
* Reindex the answers submitted by the end user
* The answers are indexed by question ID
*
* @param array $answers
* @return array
*/
private static function reindexAnswers(array $answers): array
{
return array_reduce(
array_keys($answers),
function ($carry, $key) use ($answers) {
$question_id = (int) preg_replace(self::END_USER_INPUT_NAME_REGEX, '$1', $key);
$carry[$question_id] = $answers[$key];
return $carry;
},
[]
);
}
}
5 changes: 1 addition & 4 deletions src/Form/Question.php
Expand Up @@ -46,9 +46,6 @@
*/
final class Question extends CommonDBChild
{
public const END_USER_INPUT_NAME = 'answers_%d';
public const END_USER_INPUT_NAME_REGEX = '/^_?answers_(\d+)$/';

public static $itemtype = Section::class;
public static $items_id = 'forms_sections_id';

Expand Down Expand Up @@ -126,7 +123,7 @@ protected function getForm(): Form

public function getEndUserInputName(): string
{
return sprintf(static::END_USER_INPUT_NAME, $this->getID());
return EndUserInputNameProvider::getEndUserInputName($this);
}

public function prepareInputForAdd($input)
Expand Down
88 changes: 88 additions & 0 deletions tests/functional/Glpi/Form/EndUserInputNameProvider.php
@@ -0,0 +1,88 @@
<?php

/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2024 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/

namespace tests\units\Glpi\Form;

use DbTestCase;
use Glpi\Form\QuestionType\QuestionTypeShortText;
use Glpi\Tests\FormBuilder;
use Glpi\Tests\FormTesterTrait;

class EndUserInputNameProvider extends DbTestCase
{
use FormTesterTrait;

public function testGetEndUserInputName()
{
// Create a new form
$form = $this->createForm(
(new FormBuilder())
->addQuestion('Name', QuestionTypeShortText::class)
);

// Check that the end user input name contains the question ID
// and if the regex match with the generated end user input name
foreach ($form->getQuestions() as $question) {
$this->string($question->getEndUserInputName())
->contains($question->getID())
->match(\Glpi\Form\EndUserInputNameProvider::END_USER_INPUT_NAME_REGEX);
}
}

public function testGetAnswers()
{
// Create a new form
$form = $this->createForm(
(new FormBuilder())
->addQuestion('Name', QuestionTypeShortText::class)
->addQuestion('Email', QuestionTypeShortText::class)
);

// Generate the answers
$_POST = [
$form->getQuestions()[array_keys($form->getQuestions())[0]]->getEndUserInputName() => 'John Doe',
$form->getQuestions()[array_keys($form->getQuestions())[1]]->getEndUserInputName() => 'john.doe@mail.mail',
'invalid_input' => 'invalid_value',
];

// Check that the answers are correctly indexed by question ID
$this->array(\Glpi\Form\EndUserInputNameProvider::getAnswers())
->hasSize(2)
->isEqualTo([
$form->getQuestions()[array_keys($form->getQuestions())[0]]->getID() => 'John Doe',
$form->getQuestions()[array_keys($form->getQuestions())[1]]->getID() => 'john.doe@mail.mail',
]);
}
}

0 comments on commit 79d4121

Please sign in to comment.