Partage d'export enregistré et génération asynchrone des exports

This commit is contained in:
2025-07-08 13:53:25 +00:00
parent c4cc0baa8e
commit 8bc16dadb0
447 changed files with 14134 additions and 3854 deletions

View File

@@ -0,0 +1,138 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Tests\Export\Formatter;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Export\ExportGenerationContext;
use Chill\MainBundle\Export\ExportInterface;
use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Export\Formatter\SpreadSheetFormatter;
use Chill\MainBundle\Service\RollingDate\RollingDate;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use Symfony\Component\Translation\TranslatableMessage;
/**
* @internal
*
* @coversNothing
*/
class SpreadsheetFormatterTest extends TestCase
{
use ProphecyTrait;
public function testGenerate(): void
{
$translator = $this->prophesize(\Symfony\Contracts\Translation\TranslatorInterface::class);
$translator->getLocale()->willReturn('en');
$exportManager = $this->prophesize(ExportManager::class);
$result =
[
['export_count_activity' => 1, 'person_age' => 65, 'aggregator_some' => 'label0'], // row 0
];
$exportAlias = 'count_activity_linked_to_person';
$formatterData =
['format' => 'xlsx', 'person_age_aggregator' => ['order' => 1], 'aggregator2' => ['order' => 2]];
$exportData = [];
$filtersData =
[
'person_age_filter' => ['min_age' => 18, 'max_age' => 120, 'date_calc' => new RollingDate(RollingDate::T_TODAY)],
'filter2' => [],
];
$aggregatorsData =
[
'person_age_aggregator' => ['date_age_calculation' => new RollingDate(RollingDate::T_TODAY)],
'aggregator2' => [],
];
$context =
new ExportGenerationContext($user = new User());
$export = $this->prophesize(ExportInterface::class);
$export->getTitle()->willReturn('Count activity linked to person');
$translator->trans('Count activity linked to person')->willReturn('Count activity linked to person');
$export->getQueryKeys($exportData)->willReturn(['export_count_activity']);
$export->getLabels('export_count_activity', [1], $exportData)
->willReturn(fn (int|string $value): int|string => '_header' === $value ? 'Count activities' : $value);
$translator->trans('Count activities')->willReturn('Count activities');
$exportManager->getExport($exportAlias)->willReturn($export->reveal());
$aggregator = $this->prophesize(\Chill\MainBundle\Export\AggregatorInterface::class);
$aggregator->getTitle()->willReturn('Person age');
$aggregator->getQueryKeys($aggregatorsData['person_age_aggregator'])->willReturn(['person_age']);
$aggregator->getLabels('person_age', [65], $aggregatorsData['person_age_aggregator'])
->willReturn(fn (int|string $value): int|string => '_header' === $value ? 'Group by age' : $value);
$translator->trans('Group by age')->willReturn('Group by age');
$exportManager->getAggregator('person_age_aggregator')->willReturn($aggregator->reveal());
$aggregator2 = $this->prophesize(\Chill\MainBundle\Export\AggregatorInterface::class);
$aggregator2->getTitle()->willReturn(new TranslatableMessage('Some'));
$aggregator2->getQueryKeys($aggregatorsData['aggregator2'])->willReturn(['aggregator_some']);
$aggregator2->getLabels('aggregator_some', ['label0'], $aggregatorsData['aggregator2'])
->willReturn(fn (int|string $value): TranslatableMessage => new TranslatableMessage('_header' === $value ? 'Aggregator 2 header' : $value));
$translator->trans('Aggregator 2 header', [], null, 'en')->willReturn('Aggregator 2 header');
$translator->trans('label0', [], null, 'en')->willReturn('label0');
$exportManager->getAggregator('aggregator2')->willReturn($aggregator2->reveal());
$filter = $this->prophesize(\Chill\MainBundle\Export\FilterInterface::class);
$filter->getTitle()->willReturn('Person by age');
$filter->describeAction($filtersData['person_age_filter'], $context)
->willReturn(['Filter by age, from {{ start }} to {{ end }}', ['{{ start }}' => '18', '{{ end }}' => '120']]);
$translator->trans('Filter by age, from {{ start }} to {{ end }}', ['{{ start }}' => '18', '{{ end }}' => '120'])
->willReturn('Filter by age, from 18 to 120');
$exportManager->getFilter('person_age_filter')->willReturn($filter->reveal());
$filter2 = $this->prophesize(\Chill\MainBundle\Export\FilterInterface::class);
$filter2->getTitle()->willReturn(new TranslatableMessage('Some other filter'));
$filter2->describeAction($filtersData['filter2'], $context)
->willReturn(new TranslatableMessage('Other filter description'));
$translator->trans('Other filter description', [], null, 'en')
->willReturn('Some other filter description');
$exportManager->getFilter('filter2')->willReturn($filter2->reveal());
// create the formatter
$formatter = new SpreadSheetFormatter($translator->reveal());
$formatter->setExportManager($exportManager->reveal());
$result = $formatter->generate(
$result,
$formatterData,
$exportAlias,
$exportData,
$filtersData,
$aggregatorsData,
$context,
);
$tempFile = tempnam(sys_get_temp_dir(), 'test_spreadsheet_formatter_');
file_put_contents($tempFile, $result->content);
$spreadsheet = IOFactory::load($tempFile);
$cells = $spreadsheet->getActiveSheet()->rangeToArray(
'A1:G6',
null,
false,
true,
true,
);
unlink($tempFile);
self::assertEquals('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', $result->contentType);
self::assertEquals($cells[1], ['A' => 'Count activity linked to perso…', 'B' => null, 'C' => null, 'D' => null, 'E' => null, 'F' => null, 'G' => null]);
self::assertEquals($cells[2], ['A' => null, 'B' => null, 'C' => null, 'D' => null, 'E' => null, 'F' => null, 'G' => null]);
self::assertEquals($cells[3], ['A' => 'Filter by age, from 18 to 120', 'B' => null, 'C' => null, 'D' => null, 'E' => null, 'F' => null, 'G' => null]);
self::assertEquals($cells[4], ['A' => 'Some other filter description', 'B' => null, 'C' => null, 'D' => null, 'E' => null, 'F' => null, 'G' => null]);
self::assertEquals($cells[5], ['A' => 'Group by age', 'B' => 'Aggregator 2 header', 'C' => 'Count activities', 'D' => null, 'E' => null, 'F' => null, 'G' => null]);
self::assertEquals($cells[6], ['A' => 65, 'B' => 'label0', 'C' => 1, 'D' => null, 'E' => null, 'F' => null, 'G' => null]);
}
}