Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(forms): Adding file category and related sub question type #17077

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/Form/AnswersHandler/AnswersHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,12 @@ protected function createAnswserSet(
// We need to keep track of some extra data like label and type because
// the linked question might be deleted one day but the answer must still
// be readable.
$question = $questions[$question_id];
$formatted_answers[] = [
'question' => $question_id,
'value' => $answer,
'label' => $questions[$question_id]->fields['name'],
'type' => $questions[$question_id]->fields['type'],
'value' => $question->getQuestionType()->prepareEndUserAnswer($question, $answer),
'label' => $question->fields['name'],
'type' => $question->fields['type'],
];
}

Expand Down
6 changes: 3 additions & 3 deletions src/Form/Question.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public function getExtraDatas(): ?array
*
* @return Form
*/
protected function getForm(): Form
public function getForm(): Form
{
return $this->getItem()->getItem();
}
Expand Down Expand Up @@ -154,7 +154,7 @@ private function prepareInput(&$input)

if ($question_type) {
if (isset($input['default_value'])) {
$input['default_value'] = $question_type::formatDefaultValueForDB($input['default_value']);
$input['default_value'] = $question_type->formatDefaultValueForDB($input['default_value']);
}

$extra_data = $input['extra_data'] ?? [];
Expand All @@ -167,7 +167,7 @@ private function prepareInput(&$input)
}
}

$is_extra_data_valid = $question_type::validateExtraDataInput($extra_data);
$is_extra_data_valid = $question_type->validateExtraDataInput($extra_data);

if (!$is_extra_data_valid) {
throw new \InvalidArgumentException("Invalid extra data for question");
Expand Down
10 changes: 8 additions & 2 deletions src/Form/QuestionType/AbstractQuestionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,19 @@ public function __construct()
}

#[Override]
public static function formatDefaultValueForDB(mixed $value): ?string
public function formatDefaultValueForDB(mixed $value): ?string
{
return $value; // Default value is already formatted
}

#[Override]
public static function validateExtraDataInput(array $input): bool
public function prepareEndUserAnswer(Question $question, mixed $answer): mixed
{
return $answer;
}

#[Override]
public function validateExtraDataInput(array $input): bool
{
return empty($input); // No extra data by default
}
Expand Down
4 changes: 2 additions & 2 deletions src/Form/QuestionType/AbstractQuestionTypeActors.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ abstract class AbstractQuestionTypeActors extends AbstractQuestionType
abstract public function getAllowedActorTypes(): array;

#[Override]
public static function formatDefaultValueForDB(mixed $value): ?string
public function formatDefaultValueForDB(mixed $value): ?string
{
if (is_array($value)) {
return implode(',', $value);
Expand All @@ -62,7 +62,7 @@ public static function formatDefaultValueForDB(mixed $value): ?string
}

#[Override]
public static function validateExtraDataInput(array $input): bool
public function validateExtraDataInput(array $input): bool
{
$allowed_keys = [
'is_multiple_actors'
Expand Down
6 changes: 6 additions & 0 deletions src/Form/QuestionType/QuestionTypeCategory.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ enum QuestionTypeCategory: string
*/
case REQUEST_TYPE = "request_type";

/**
* Question that expect a file upload
*/
case FILE = "file";

/**
* Get category label
* @return string
Expand All @@ -83,6 +88,7 @@ public function getLabel(): string
self::ACTORS => __("Actors"),
self::URGENCY => __("Urgency"),
self::REQUEST_TYPE => __("Request type"),
self::FILE => __("File")
};
}
}
2 changes: 1 addition & 1 deletion src/Form/QuestionType/QuestionTypeDateTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public function isTimeEnabled(?Question $question): bool
}

#[Override]
public static function validateExtraDataInput(array $input): bool
public function validateExtraDataInput(array $input): bool
{
$allowed_keys = [
'is_default_value_current_time',
Expand Down
140 changes: 140 additions & 0 deletions src/Form/QuestionType/QuestionTypeFile.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?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\QuestionType;

use Document;
use Glpi\Application\View\TemplateRenderer;
use Glpi\Form\Question;
use Override;

final class QuestionTypeFile extends AbstractQuestionType
{
#[Override]
public function prepareEndUserAnswer(Question $question, mixed $answer): mixed
{
$form = $question->getForm();
$document = new Document();
$document_ids = [];
foreach ($answer as $file) {
$document_ids[] = $document->add([
'name' => sprintf('%s - %s', $form->getName(), $question->getName()),
'entities_id' => $form->getEntityID(),
'is_recursive' => $form->isRecursive(),
'_filename' => [$file],
'_prefix_filename' => [$_POST['_prefix_' . $question->getEndUserInputName()]],
]);
}

return $document_ids;
}

#[Override]
public function renderAdministrationTemplate(?Question $question): string
{
$template = <<<TWIG
{% import 'components/form/fields_macros.html.twig' as fields %}

{{ fields.fileField(
'default_value',
'',
'',
{
'init' : question is not null ? true: false,
'no_label' : true,
'full_width' : true,
}
) }}
TWIG;

$twig = TemplateRenderer::getInstance();
return $twig->renderFromStringTemplate($template, [
'question' => $question
]);
}

#[Override]
public function renderAdministrationOptionsTemplate(?Question $question): string
{
return '';
}

#[Override]
public function renderEndUserTemplate(Question $question): string
{
$template = <<<TWIG
{% import 'components/form/fields_macros.html.twig' as fields %}

{{ fields.fileField(
question.getEndUserInputName(),
"",
"",
{
'init' : true,
'no_label' : true,
'full_width' : true,
}
) }}
TWIG;

$twig = TemplateRenderer::getInstance();
return $twig->renderFromStringTemplate($template, [
'question' => $question
]);
}

#[Override]
public function renderAnswerTemplate($answer): string
{
$template = <<<TWIG
{% for document in documents %}
<div class="form-control-plaintext">
{{ document.getLink()|raw }}
</div>
{% endfor %}
TWIG;

$twig = TemplateRenderer::getInstance();
return $twig->renderFromStringTemplate($template, [
'documents' => array_map(fn($document_id) => (new Document())->getById($document_id), $answer)
]);
}

#[Override]
public function getCategory(): QuestionTypeCategory
{
return QuestionTypeCategory::FILE;
}
}
14 changes: 12 additions & 2 deletions src/Form/QuestionType/QuestionTypeInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function __construct();
* @param mixed $value The default value to format.
* @return string
*/
public static function formatDefaultValueForDB(mixed $value): ?string;
public function formatDefaultValueForDB(mixed $value): ?string;

/**
* Validate the input for extra data of the question.
Expand All @@ -61,7 +61,17 @@ public static function formatDefaultValueForDB(mixed $value): ?string;
*
* @return bool
*/
public static function validateExtraDataInput(array $input): bool;
public function validateExtraDataInput(array $input): bool;

/**
* Prepare the answer for the end user.
* This method is called before saving the answer.
*
* @param Question $question The question data.
* @param mixed $answer The raw answer data.
* @return mixed The prepared answer data.
*/
public function prepareEndUserAnswer(Question $question, mixed $answer): mixed;

/**
* Render the administration template for the given question.
Expand Down
14 changes: 12 additions & 2 deletions tests/units/Glpi/Form/AnswersSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@
use Glpi\Form\Destination\FormDestinationTicket;
use Glpi\Form\QuestionType\QuestionTypeDateTime;
use Glpi\Form\QuestionType\QuestionTypeEmail;
use Glpi\Form\QuestionType\QuestionTypeFile;
use Glpi\Form\QuestionType\QuestionTypeLongText;
use Glpi\Form\QuestionType\QuestionTypeNumber;
use Glpi\Form\QuestionType\QuestionTypeRequestType;
use Glpi\Form\QuestionType\QuestionTypeShortText;
use Glpi\Form\QuestionType\QuestionTypesManager;
use Glpi\Form\QuestionType\QuestionTypeTime;
use Glpi\Form\QuestionType\QuestionTypeUrgency;
use Glpi\Tests\FormBuilder;
use Glpi\Tests\FormTesterTrait;
Expand Down Expand Up @@ -259,7 +259,16 @@ public function testShowForm(): void
->addQuestion("Assignee", QuestionTypeAssignee::class)
->addQuestion("Urgency", QuestionTypeUrgency::class)
->addQuestion("Request type", QuestionTypeRequestType::class)
->addQuestion("File", QuestionTypeFile::class)
);

// File question type requires an uploaded file
$unique_id = uniqid();
$filename = $unique_id . '-test-show-form-question-type-file.txt';
copy(__DIR__ . '/../../../fixtures/uploads/bar.txt', GLPI_TMP_DIR . '/' . $filename);
$question = \Glpi\Form\Question::getById($this->getQuestionId($form, "File"));
$_POST['_prefix_' . $question->getEndUserInputName()] = $unique_id;

$answers_set = $answers_handler->saveAnswers($form, [
$this->getQuestionId($form, "Name") => "Pierre Paul Jacques",
$this->getQuestionId($form, "Age") => 20,
Expand All @@ -282,7 +291,8 @@ public function testShowForm(): void
Supplier::getForeignKeyField() . '-1'
],
$this->getQuestionId($form, "Urgency") => 2,
$this->getQuestionId($form, "Request type") => 1
$this->getQuestionId($form, "Request type") => 1,
$this->getQuestionId($form, "File") => [$filename]
], \Session::getLoginUserID());

// Ensure we used every possible questions types
Expand Down
10 changes: 9 additions & 1 deletion tests/units/Glpi/Form/QuestionType/QuestionTypesManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ public function testGetCategories(): void
QuestionTypeCategory::DATE_AND_TIME,
QuestionTypeCategory::ACTORS,
QuestionTypeCategory::URGENCY,
QuestionTypeCategory::REQUEST_TYPE
QuestionTypeCategory::REQUEST_TYPE,
QuestionTypeCategory::FILE,
];

// Manual array comparison, `isEqualTo` doesn't seem to work properly
Expand Down Expand Up @@ -146,6 +147,13 @@ protected function testGetTypesForCategoryProvider(): iterable
new \Glpi\Form\QuestionType\QuestionTypeRequestType(),
]
];

yield [
QuestionTypeCategory::FILE,
[
new \Glpi\Form\QuestionType\QuestionTypeFile(),
]
];
}

/**
Expand Down