diff --git a/src/Bundle/ChillMainBundle/Controller/SavedExportController.php b/src/Bundle/ChillMainBundle/Controller/SavedExportController.php
index ddda96e19..20b9bf1c5 100644
--- a/src/Bundle/ChillMainBundle/Controller/SavedExportController.php
+++ b/src/Bundle/ChillMainBundle/Controller/SavedExportController.php
@@ -14,6 +14,7 @@ namespace Chill\MainBundle\Controller;
use Chill\MainBundle\Entity\ExportGeneration;
use Chill\MainBundle\Entity\SavedExport;
use Chill\MainBundle\Entity\User;
+use Chill\MainBundle\Export\ExportDescriptionHelper;
use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Form\SavedExportType;
use Chill\MainBundle\Security\Authorization\ExportGenerationVoter;
@@ -44,6 +45,7 @@ final readonly class SavedExportController
private Security $security,
private TranslatorInterface $translator,
private UrlGeneratorInterface $urlGenerator,
+ private ExportDescriptionHelper $exportDescriptionHelper,
) {}
#[Route(path: '/{_locale}/exports/saved/{id}/delete', name: 'chill_main_export_saved_delete')]
@@ -107,7 +109,21 @@ final readonly class SavedExportController
$request->query->has('title') ? $request->query->get('title') : $title
);
- return $this->handleEdit($savedExport, $request);
+ if ($exportGeneration->isLinkedToSavedExport()) {
+ $savedExport->setDescription($exportGeneration->getSavedExport()->getDescription());
+ } else {
+ $savedExport->setDescription(
+ implode(
+ "\n",
+ array_map(
+ fn (string $item) => '- '.$item."\n",
+ $this->exportDescriptionHelper->describe($savedExport->getExportAlias(), $savedExport->getOptions(), includeExportTitle: false)
+ )
+ )
+ );
+ }
+
+ return $this->handleEdit($savedExport, $request, true);
}
#[Route(path: '/exports/saved/duplicate-from-saved-export/{id}/new', name: 'chill_main_export_saved_duplicate')]
@@ -138,7 +154,7 @@ final readonly class SavedExportController
}
- private function handleEdit(SavedExport $savedExport, Request $request): Response
+ private function handleEdit(SavedExport $savedExport, Request $request, bool $showWarningAutoGeneratedDescription = false): Response
{
$form = $this->formFactory->create(SavedExportType::class, $savedExport);
$form->handleRequest($request);
@@ -161,6 +177,7 @@ final readonly class SavedExportController
'@ChillMain/SavedExport/new.html.twig',
[
'form' => $form->createView(),
+ 'showWarningAutoGeneratedDescription' => $showWarningAutoGeneratedDescription,
],
),
);
diff --git a/src/Bundle/ChillMainBundle/Export/ExportDescriptionHelper.php b/src/Bundle/ChillMainBundle/Export/ExportDescriptionHelper.php
new file mode 100644
index 000000000..3016f2f79
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Export/ExportDescriptionHelper.php
@@ -0,0 +1,74 @@
+
+ */
+ public function describe(string $exportAlias, array $exportOptions, bool $includeExportTitle = true): array
+ {
+ $output = [];
+ $denormalized = $this->exportConfigNormalizer->denormalizeConfig($exportAlias, $exportOptions);
+ $user = $this->security->getUser();
+
+ if ($includeExportTitle) {
+ $output[] = $this->trans($this->exportManager->getExport($exportAlias)->getTitle());
+ }
+
+ if (!$user instanceof User) {
+ return $output;
+ }
+ $context = new ExportGenerationContext($user);
+
+ foreach ($this->exportConfigProcessor->retrieveUsedFilters($denormalized['filters']) as $name => $filter) {
+ $output[] = $this->trans($filter->describeAction($denormalized['filters'][$name]['form'], $context));
+ }
+
+ foreach ($this->exportConfigProcessor->retrieveUsedAggregators($denormalized['aggregators']) as $name => $aggregator) {
+ $output[] = $this->trans($aggregator->getTitle());
+ }
+
+ return $output;
+ }
+
+ private function trans(string|TranslatableInterface|array $translatable): string
+ {
+ if (is_string($translatable)) {
+ return $this->translator->trans($translatable);
+ }
+
+ if ($translatable instanceof TranslatableInterface) {
+ return $translatable->trans($this->translator);
+ }
+
+ // array case
+ return $this->translator->trans($translatable[0], $translatable[1] ?? []);
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/new.html.twig b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/new.html.twig
index 3fddcd270..d6e3e3eee 100644
--- a/src/Bundle/ChillMainBundle/Resources/views/SavedExport/new.html.twig
+++ b/src/Bundle/ChillMainBundle/Resources/views/SavedExport/new.html.twig
@@ -18,6 +18,13 @@
{{ form_start(form) }}
{{ form_row(form.title) }}
+
+ {% if showWarningAutoGeneratedDescription|default(false) %}
+
+ {{ 'saved_export.Alert auto generated description'|trans }}
+
+ {% endif %}
+
{{ form_row(form.description) }}
{% if form.share is defined %}
diff --git a/src/Bundle/ChillMainBundle/Tests/Export/ExportDescriptionHelperTest.php b/src/Bundle/ChillMainBundle/Tests/Export/ExportDescriptionHelperTest.php
new file mode 100644
index 000000000..75638dd0f
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Tests/Export/ExportDescriptionHelperTest.php
@@ -0,0 +1,174 @@
+prophesize(Security::class);
+ $security->getUser()->willReturn($user = new User());
+
+ $exportConfigNormalizer = $this->prophesize(ExportConfigNormalizer::class);
+ $exportConfigNormalizer->denormalizeConfig('my_export', Argument::type('array'))->willReturn($options);
+
+ $export = $this->prophesize(ExportInterface::class);
+ $export->getTitle()->willReturn('Title');
+
+ $myFilterString = $this->prophesize(FilterInterface::class);
+ $myFilterString->describeAction(Argument::type('array'), Argument::type(ExportGenerationContext::class))->willReturn($string0 = 'This is a filter description');
+ $myFilterArray = $this->prophesize(FilterInterface::class);
+ $myFilterArray->describeAction(Argument::type('array'), Argument::type(ExportGenerationContext::class))->willReturn([$string1 = 'This is a filter with %argument%', $arg1 = ['%argument%' => 'zero']]);
+ $myFilterTranslatable = $this->prophesize(FilterInterface::class);
+ $myFilterTranslatable->describeAction(Argument::type('array'), Argument::type(ExportGenerationContext::class))
+ ->willReturn(new class () implements TranslatableInterface {
+ public function trans(TranslatorInterface $translator, ?string $locale = null): string
+ {
+ return 'translatable';
+ }
+ });
+
+ $myAggregator = $this->prophesize(AggregatorInterface::class);
+ $myAggregator->getTitle()->willReturn('Some aggregator');
+
+ $token = new UsernamePasswordToken($user, 'main', ['ROLE_USER']);
+ $tokenStorage = new TokenStorage();
+ $tokenStorage->setToken($token);
+
+ $exportManager = new ExportManager(
+ new NullLogger(),
+ $security->reveal(),
+ $this->prophesize(AuthorizationHelperInterface::class)->reveal(),
+ $tokenStorage,
+ ['my_export' => $export->reveal()],
+ ['my_aggregator' => $myAggregator->reveal()],
+ [
+ 'my_filter_string' => $myFilterString->reveal(),
+ 'my_filter_array' => $myFilterArray->reveal(),
+ 'my_filter_translatable' => $myFilterTranslatable->reveal(),
+ ],
+ [],
+ );
+
+ $exportConfigProcessor = new ExportConfigProcessor($exportManager);
+
+ $translator = $this->prophesize(TranslatorInterface::class);
+ $translator->trans('Title')->shouldBeCalled()->willReturn('Title');
+ $translator->trans($string0)->shouldBeCalled()->willReturn($string0);
+ $translator->trans($string1, $arg1)->shouldBeCalled()->willReturn($string1);
+ $translator->trans('Some aggregator')->shouldBeCalled()->willReturn('Some aggregator');
+
+ $exportDescriptionHelper = new ExportDescriptionHelper(
+ $exportManager,
+ $exportConfigNormalizer->reveal(),
+ $exportConfigProcessor,
+ $translator->reveal(),
+ $security->reveal(),
+ );
+
+ $actual = $exportDescriptionHelper->describe('my_export', $options);
+
+ self::assertIsArray($actual);
+ self::assertEquals($actual[0], 'Title');
+ self::assertEquals($actual[1], 'This is a filter description');
+ self::assertEquals($actual[2], 'This is a filter with %argument%');
+ self::assertEquals($actual[3], 'translatable');
+ self::assertEquals($actual[4], 'Some aggregator');
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php b/src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php
index 6004a6012..d52129af7 100644
--- a/src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php
+++ b/src/Bundle/ChillMainBundle/Tests/Export/ExportManagerTest.php
@@ -348,7 +348,6 @@ final class ExportManagerTest extends KernelTestCase
$logger ?? self::getContainer()->get(LoggerInterface::class),
$authorizationChecker ?? self::getContainer()->get('security.authorization_checker'),
$authorizationHelper ?? self::getContainer()->get('chill.main.security.authorization.helper'),
- $tokenStorage,
$exports,
$aggregators,
$filters,
diff --git a/src/Bundle/ChillMainBundle/config/services/export.yaml b/src/Bundle/ChillMainBundle/config/services/export.yaml
index acbb53f8a..3027532e1 100644
--- a/src/Bundle/ChillMainBundle/config/services/export.yaml
+++ b/src/Bundle/ChillMainBundle/config/services/export.yaml
@@ -18,6 +18,8 @@ services:
Chill\MainBundle\Export\ExportConfigProcessor: ~
+ Chill\MainBundle\Export\ExportDescriptionHelper: ~
+
chill.main.export_element_validator:
class: Chill\MainBundle\Validator\Constraints\Export\ExportElementConstraintValidator
tags:
diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml
index a2d718143..1141f50fc 100644
--- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml
+++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml
@@ -807,6 +807,7 @@ saved_export:
Duplicated: Dupliqué
Options updated successfully: La configuration de l'export a été mise à jour
Share: Partage
+ Alert auto generated description: La description ci-dessous a été générée automatiquement, comme si l'export était exécutée immédiatement. Veillez à l'adapter pour tenir compte des paramètres qui peuvent être modifiés (utilisateurs courant, dates glissantes, etc.).
absence:
# single letter for absence