diff --git a/src/Bundle/ChillMainBundle/Controller/ExportController.php b/src/Bundle/ChillMainBundle/Controller/ExportController.php index 04c771365..70d7f10a8 100644 --- a/src/Bundle/ChillMainBundle/Controller/ExportController.php +++ b/src/Bundle/ChillMainBundle/Controller/ExportController.php @@ -25,6 +25,7 @@ use Chill\MainBundle\Form\Type\Export\FormatterType; use Chill\MainBundle\Form\Type\Export\PickCenterType; use Chill\MainBundle\Repository\SavedExportOrExportGenerationRepository; use Chill\MainBundle\Security\Authorization\SavedExportVoter; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; @@ -117,7 +118,7 @@ class ExportController extends AbstractController $options = match ($step) { 'export', 'generate_export' => [ 'export_alias' => $alias, - 'picked_centers' => $exportManager->getPickedCenters($data['centers'] ?? []), + 'picked_centers' => $this->exportFormHelper->getPickedCenters($data), ], 'formatter', 'generate_formatter' => [ 'export_alias' => $alias, @@ -337,9 +338,15 @@ class ExportController extends AbstractController if ($this->filterStatsByCenters) { $formCenters = $this->createCreateFormExport($alias, 'generate_centers', [], null); $formCenters->submit($dataCenters); - $dataCenters = $formCenters->getData(); + $dataAsCollection = $formCenters->getData()['centers']; + $centers = $dataAsCollection['centers']; + $regroupments = $dataAsCollection['regroupments']; + $dataCenters = [ + 'centers' => $centers instanceof Collection ? $centers->toArray() : $centers, + 'regroupments' => $regroupments instanceof Collection ? $regroupments->toArray() : $regroupments, + ]; } else { - $dataCenters = ['centers' => []]; + $dataCenters = ['centers' => [], 'regroupments' => []]; } $formExport = $this->createCreateFormExport($alias, 'generate_export', $dataCenters, null); @@ -358,7 +365,7 @@ class ExportController extends AbstractController } return [ - 'centers' => $dataCenters['centers'], + 'centers' => ['centers' => $dataCenters['centers'], 'regroupments' => $dataCenters['regroupments'] ?? []], 'export' => $dataExport['export']['export'] ?? [], 'filters' => $dataExport['export']['filters'] ?? [], 'aggregators' => $dataExport['export']['aggregators'] ?? [], @@ -401,7 +408,7 @@ class ExportController extends AbstractController false === $exportManager->isGrantedForElement( $export, null, - $exportManager->getPickedCenters($data['centers']) + $this->exportFormHelper->getPickedCenters($data['centers']), ) ) { throw $this->createAccessDeniedException('you do not have access to this export for those centers'); @@ -411,7 +418,7 @@ class ExportController extends AbstractController 'centers_step_raw', $request->request->all() ); - $this->session->set('centers_step', $data); + $this->session->set('centers_step', $data['centers']); return $this->redirectToRoute('chill_main_export_new', [ 'step' => $this->getNextStep('centers', $export), diff --git a/src/Bundle/ChillMainBundle/Entity/Regroupment.php b/src/Bundle/ChillMainBundle/Entity/Regroupment.php index 389eceb31..d28784210 100644 --- a/src/Bundle/ChillMainBundle/Entity/Regroupment.php +++ b/src/Bundle/ChillMainBundle/Entity/Regroupment.php @@ -102,4 +102,22 @@ class Regroupment return $this; } + + /** + * Return true if the given center is contained into this regroupment. + */ + public function containsCenter(Center $center): bool + { + return $this->centers->contains($center); + } + + /** + * Return true if at least one of the given centers is contained into this regroupment. + * + * @param list
$centers + */ + public function containsAtLeastOneCenter(array $centers): bool + { + return array_reduce($centers, fn (bool $carry, Center $center) => $carry || $this->containsCenter($center), false); + } } diff --git a/src/Bundle/ChillMainBundle/Export/Exception/ExportGenerationException.php b/src/Bundle/ChillMainBundle/Export/Exception/ExportGenerationException.php new file mode 100644 index 000000000..0c06c4a7d --- /dev/null +++ b/src/Bundle/ChillMainBundle/Export/Exception/ExportGenerationException.php @@ -0,0 +1,14 @@ +, export: array{form: array, version: int}, filters: array, version: int}>, aggregators: array, version: int}>, pick_formatter: string, formatter: array{form: array, version: int}} + * @phpstan-type NormalizedData array{centers: array{centers: list, regroupments: list}, export: array{form: array, version: int}, filters: array, version: int}>, aggregators: array, version: int}>, pick_formatter: string, formatter: array{form: array, version: int}} */ class ExportConfigNormalizer { public function __construct( private readonly ExportManager $exportManager, private readonly CenterRepositoryInterface $centerRepository, + private readonly RegroupmentRepository $regroupmentRepository, ) {} /** @@ -42,10 +45,10 @@ class ExportConfigNormalizer ], ]; - $serialized['centers'] = array_values( - array_map(static fn (Center $center) => $center->getId(), $formData['centers']) - ); - + $serialized['centers'] = [ + 'centers' => array_values(array_map(static fn (Center $center) => $center->getId(), $formData['centers']['centers'] ?? [])), + 'regroupments' => array_values(array_map(static fn (Regroupment $group) => $group->getId(), $formData['centers']['regroupments'] ?? [])), + ]; $filtersSerialized = []; foreach ($formData[ExportType::FILTER_KEY] as $alias => $filterData) { @@ -116,7 +119,10 @@ class ExportConfigNormalizer 'aggregators' => $aggregatorsConfig, 'pick_formatter' => $serializedData['pick_formatter'], 'formatter' => $formater->denormalizeFormData($serializedData['formatter']['form'], $serializedData['formatter']['version']), - 'centers' => array_filter(array_map(fn (int $id) => $this->centerRepository->find($id), $serializedData['centers']), fn ($item) => null !== $item), + 'centers' => [ + 'centers' => array_values(array_filter(array_map(fn (int $id) => $this->centerRepository->find($id), $serializedData['centers']['centers']), fn ($item) => null !== $item)), + 'regroupments' => array_values(array_filter(array_map(fn (int $id) => $this->regroupmentRepository->find($id), $serializedData['centers']['regroupments']), fn ($item) => null !== $item)), + ], ]; } } diff --git a/src/Bundle/ChillMainBundle/Export/ExportFormHelper.php b/src/Bundle/ChillMainBundle/Export/ExportFormHelper.php index f2c015351..faccbf0f3 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportFormHelper.php +++ b/src/Bundle/ChillMainBundle/Export/ExportFormHelper.php @@ -11,11 +11,14 @@ declare(strict_types=1); namespace Chill\MainBundle\Export; +use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\ExportGeneration; use Chill\MainBundle\Entity\SavedExport; use Chill\MainBundle\Form\Type\Export\ExportType; use Chill\MainBundle\Form\Type\Export\FilterType; use Chill\MainBundle\Security\Authorization\AuthorizationHelperForCurrentUserInterface; +use Chill\MainBundle\Service\Regroupement\CenterRegroupementResolver; +use Doctrine\Common\Collections\Collection; final readonly class ExportFormHelper { @@ -23,12 +26,13 @@ final readonly class ExportFormHelper private AuthorizationHelperForCurrentUserInterface $authorizationHelper, private ExportManager $exportManager, private ExportConfigNormalizer $configNormalizer, + private CenterRegroupementResolver $centerRegroupementResolver, ) {} public function getDefaultData(string $step, DirectExportInterface|ExportInterface $export, array $options = []): array { return match ($step) { - 'centers', 'generate_centers' => ['centers' => $this->authorizationHelper->getReachableCenters($export->requiredRole())], + 'centers', 'generate_centers' => ['centers' => $this->authorizationHelper->getReachableCenters($export->requiredRole()), 'regroupments' => []], 'export', 'generate_export' => ['export' => $this->getDefaultDataStepExport($export, $options)], 'formatter', 'generate_formatter' => ['formatter' => $this->getDefaultDataStepFormatter($options)], default => throw new \LogicException('step not allowed : '.$step), @@ -132,4 +136,24 @@ final readonly class ExportFormHelper 'formatter' => $data['formatter'], ]; } + + /** + * Get the Center picked by the user for this export. The data are + * extracted from the PickCenterType data. + * + * @param array $data the data as given by the @see{Chill\MainBundle\Form\Type\Export\PickCenterType} + * + * @return list
+ */ + public function getPickedCenters(array $data): array + { + if (!array_key_exists('centers', $data) || !array_key_exists('regroupments', $data)) { + throw new \RuntimeException('array has not the expected shape'); + } + + $centers = $data['centers'] instanceof Collection ? $data['centers']->toArray() : $data['centers']; + $regroupments = $data['regroupments'] instanceof Collection ? $data['regroupments']->toArray() : $data['regroupments']; + + return $this->centerRegroupementResolver->resolveCenters(dump($regroupments), dump($centers)); + } } diff --git a/src/Bundle/ChillMainBundle/Export/ExportGenerator.php b/src/Bundle/ChillMainBundle/Export/ExportGenerator.php index f1a4d386b..20b87ebe9 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportGenerator.php +++ b/src/Bundle/ChillMainBundle/Export/ExportGenerator.php @@ -13,7 +13,11 @@ namespace Chill\MainBundle\Export; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\User; +use Chill\MainBundle\Export\Exception\UnauthorizedGenerationException; use Chill\MainBundle\Form\Type\Export\ExportType; +use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; +use Chill\MainBundle\Service\Regroupement\CenterRegroupementResolver; +use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\QueryBuilder; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Response; @@ -27,14 +31,17 @@ final readonly class ExportGenerator private ExportManager $exportManager, private ExportConfigNormalizer $configNormalizer, private LoggerInterface $logger, + private AuthorizationHelperInterface $authorizationHelper, + private CenterRegroupementResolver $centerRegroupementResolver, ) {} public function generate(string $exportAlias, array $configuration, ?User $byUser = null): FormattedExportGeneration { $data = $this->configNormalizer->denormalizeConfig($exportAlias, $configuration); - $centers = $data['centers']; - $export = $this->exportManager->getExport($exportAlias); + + $centers = $this->filterCenters($byUser, $data['centers']['centers'], $data['centers']['regroupments'], $export); + $context = new ExportGenerationContext($byUser); if ($export instanceof DirectExportInterface) { @@ -94,6 +101,7 @@ final readonly class ExportGenerator } } + /** @phpstan-ignore-next-line the method "generate" is not yet implemented on all formatters */ if (method_exists($formatter, 'generate')) { return $formatter->generate( $result, @@ -119,6 +127,29 @@ final readonly class ExportGenerator return new FormattedExportGeneration($generatedExport->getContent(), $generatedExport->headers->get('content-type')); } + private function filterCenters(User $byUser, array $centers, array $regroupements, ExportInterface|DirectExportInterface $export): array + { + $authorizedCenters = new ArrayCollection($this->authorizationHelper->getReachableCenters($byUser, $export->requiredRole())); + if ($authorizedCenters->isEmpty()) { + throw new UnauthorizedGenerationException('No authorized centers'); + } + + $wantedCenters = $this->centerRegroupementResolver->resolveCenters($regroupements, $centers); + + $resolvedCenters = []; + foreach ($wantedCenters as $wantedCenter) { + if ($authorizedCenters->contains($wantedCenter)) { + $resolvedCenters[] = $wantedCenter; + } + } + + if ([] == $resolvedCenters) { + throw new UnauthorizedGenerationException('No common centers between wanted centers and authorized centers'); + } + + return $resolvedCenters; + } + /** * parse the data to retrieve the used filters and aggregators. * diff --git a/src/Bundle/ChillMainBundle/Export/ExportManager.php b/src/Bundle/ChillMainBundle/Export/ExportManager.php index c723bba68..fbc81caa3 100644 --- a/src/Bundle/ChillMainBundle/Export/ExportManager.php +++ b/src/Bundle/ChillMainBundle/Export/ExportManager.php @@ -348,19 +348,6 @@ class ExportManager } } - /** - * Get the Center picked by the user for this export. The data are - * extracted from the PickCenterType data. - * - * @param array $data the data from a PickCenterType - * - * @return \Chill\MainBundle\Entity\Center[] the picked center - */ - public function getPickedCenters(array $data): array - { - return $data; - } - /** * get the aggregators types used in the form export data. * diff --git a/src/Bundle/ChillMainBundle/Form/DataMapper/ExportPickCenterDataMapper.php b/src/Bundle/ChillMainBundle/Form/DataMapper/ExportPickCenterDataMapper.php deleted file mode 100644 index 2a19c8e0b..000000000 --- a/src/Bundle/ChillMainBundle/Form/DataMapper/ExportPickCenterDataMapper.php +++ /dev/null @@ -1,56 +0,0 @@ - $form */ - $form = iterator_to_array($forms); - - $form['center']->setData($viewData); - - // NOTE: we do not map back the regroupments - } - - public function mapFormsToData(\Traversable $forms, &$viewData): void - { - /** @var array $forms */ - $forms = iterator_to_array($forms); - - $centers = []; - - foreach ($forms['center']->getData() as $center) { - $centers[spl_object_hash($center)] = $center; - } - - if (\array_key_exists('regroupment', $forms)) { - /** @var Regroupment $regroupment */ - foreach ($forms['regroupment']->getData() as $regroupment) { - foreach ($regroupment->getCenters() as $center) { - $centers[spl_object_hash($center)] = $center; - } - } - } - - $viewData = array_values($centers); - } -} diff --git a/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php b/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php index fa8caf488..9196b05c0 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/Export/PickCenterType.php @@ -14,9 +14,9 @@ namespace Chill\MainBundle\Form\Type\Export; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Regroupment; use Chill\MainBundle\Export\ExportManager; -use Chill\MainBundle\Form\DataMapper\ExportPickCenterDataMapper; use Chill\MainBundle\Repository\RegroupmentRepository; use Chill\MainBundle\Security\Authorization\AuthorizationHelperForCurrentUserInterface; +use Chill\MainBundle\Service\Regroupement\RegroupementFiltering; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -27,27 +27,26 @@ use Symfony\Component\OptionsResolver\OptionsResolver; */ final class PickCenterType extends AbstractType { - public const CENTERS_IDENTIFIERS = 'c'; - public function __construct( private readonly ExportManager $exportManager, private readonly RegroupmentRepository $regroupmentRepository, private readonly AuthorizationHelperForCurrentUserInterface $authorizationHelper, + private readonly RegroupementFiltering $regroupementFiltering, ) {} public function buildForm(FormBuilderInterface $builder, array $options) { $export = $this->exportManager->getExport($options['export_alias']); $centers = $this->authorizationHelper->getReachableCenters( - $export->requiredRole() + $export->requiredRole(), ); $centersActive = array_filter($centers, fn (Center $c) => $c->getIsActive()); // order alphabetically - usort($centersActive, fn (Center $a, Center $b) => $a->getCenter() <=> $b->getName()); + usort($centersActive, fn (Center $a, Center $b) => $a->getName() <=> $b->getName()); - $builder->add('center', EntityType::class, [ + $builder->add('centers', EntityType::class, [ 'class' => Center::class, 'choices' => $centersActive, 'label' => 'center', @@ -56,18 +55,22 @@ final class PickCenterType extends AbstractType 'choice_label' => static fn (Center $c) => $c->getName(), ]); - if (\count($this->regroupmentRepository->findAllActive()) > 0) { - $builder->add('regroupment', EntityType::class, [ + $groups = $this->regroupementFiltering + ->filterContainsAtLeastOneCenter($this->regroupmentRepository->findAllActive(), $centersActive); + + // order alphabetically + usort($groups, fn (Regroupment $a, Regroupment $b) => $a->getName() <=> $b->getName()); + + if (\count($groups) > 0) { + $builder->add('regroupments', EntityType::class, [ 'class' => Regroupment::class, 'label' => 'regroupment', 'multiple' => true, 'expanded' => true, - 'choices' => $this->regroupmentRepository->findAllActive(), + 'choices' => $groups, 'choice_label' => static fn (Regroupment $r) => $r->getName(), ]); } - - $builder->setDataMapper(new ExportPickCenterDataMapper()); } public function configureOptions(OptionsResolver $resolver) diff --git a/src/Bundle/ChillMainBundle/Resources/views/Export/new_centers_step.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Export/new_centers_step.html.twig index 2e2dc0ec6..42d2d4574 100644 --- a/src/Bundle/ChillMainBundle/Resources/views/Export/new_centers_step.html.twig +++ b/src/Bundle/ChillMainBundle/Resources/views/Export/new_centers_step.html.twig @@ -40,15 +40,15 @@

{{ 'Center'|trans }}

- {{ form_widget(form.centers.center) }} + {{ form_widget(form.centers.centers) }}
- {% if form.centers.regroupment is defined %} + {% if form.centers.regroupments is defined %}

{{ 'Pick aggregated centers'|trans }}

- {{ form_widget(form.centers.regroupment) }} + {{ form_widget(form.centers.regroupments) }} {% endif %} diff --git a/src/Bundle/ChillMainBundle/Service/Regroupement/CenterRegroupementResolver.php b/src/Bundle/ChillMainBundle/Service/Regroupement/CenterRegroupementResolver.php new file mode 100644 index 000000000..9f1813c5c --- /dev/null +++ b/src/Bundle/ChillMainBundle/Service/Regroupement/CenterRegroupementResolver.php @@ -0,0 +1,44 @@ + $groups + * @param list
$centers + * + * @return list
+ */ + public function resolveCenters(array $groups, array $centers = []): array + { + $centersByHash = []; + + foreach ($groups as $group) { + foreach ($group->getCenters() as $center) { + $centersByHash[spl_object_hash($center)] = $center; + } + } + + foreach ($centers as $center) { + $centersByHash[spl_object_hash($center)] = $center; + } + + return array_values($centersByHash); + } +} diff --git a/src/Bundle/ChillMainBundle/Service/Regroupement/RegroupementFiltering.php b/src/Bundle/ChillMainBundle/Service/Regroupement/RegroupementFiltering.php new file mode 100644 index 000000000..76e4a892a --- /dev/null +++ b/src/Bundle/ChillMainBundle/Service/Regroupement/RegroupementFiltering.php @@ -0,0 +1,37 @@ + $group->containsAtLeastOneCenter($centers)), + ); + } +} diff --git a/src/Bundle/ChillMainBundle/Tests/Export/ExportConfigNormalizerTest.php b/src/Bundle/ChillMainBundle/Tests/Export/ExportConfigNormalizerTest.php index cf4518ccb..276e4e6ee 100644 --- a/src/Bundle/ChillMainBundle/Tests/Export/ExportConfigNormalizerTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Export/ExportConfigNormalizerTest.php @@ -66,7 +66,7 @@ class ExportConfigNormalizerTest extends TestCase $center->getId()->willReturn(10); $formData = [ - 'centers' => [$center->reveal()], + 'centers' => ['centers' => [$center->reveal()]], 'export' => ['test' => '0'], 'filters' => [ 'filterEnabled' => ['enabled' => true, 'form' => ['test' => '0']], @@ -82,6 +82,7 @@ class ExportConfigNormalizerTest extends TestCase $expected = [ 'export' => ['form' => ['test' => '0'], 'version' => 1], + 'centers' => ['centers' => [10], 'regroupments' => []], 'filters' => [ 'filtersEnabled' => ['enabled' => true, 'form' => ['test' => '0'], 'version' => 1], 'filterDisabled' => ['enabled' => false], @@ -95,7 +96,6 @@ class ExportConfigNormalizerTest extends TestCase 'form' => ['test' => '0'], 'version' => 1, ], - 'centers' => [10], ]; $exportConfigNormalizer = new ExportConfigNormalizer($exportManager->reveal(), $this->prophesize(CenterRepositoryInterface::class)->reveal()); @@ -137,7 +137,7 @@ class ExportConfigNormalizerTest extends TestCase $centerRepository->find(10)->willReturn($center = new Center()); $serialized = [ - 'centers' => [10], + 'centers' => ['regroupments' => [], 'centers' => [10]], 'export' => ['form' => ['test' => '0'], 'version' => 1], 'filters' => [ 'filterEnabled' => ['enabled' => true, 'form' => ['test' => '0'], 'version' => 1], @@ -166,7 +166,7 @@ class ExportConfigNormalizerTest extends TestCase ], 'pick_formatter' => 'xlsx', 'formatter' => ['test' => '0'], - 'centers' => [$center], + 'centers' => ['centers' => [$center], 'regroupments' => []], ]; $exportConfigNormalizer = new ExportConfigNormalizer($exportManager->reveal(), $centerRepository->reveal()); @@ -209,7 +209,7 @@ class ExportConfigNormalizerTest extends TestCase $center->getId()->willReturn(10); $formData = [ - 'centers' => [$center->reveal()], + 'centers' => ['centers' => [$center->reveal()]], 'export' => [], 'filters' => [ 'filterEnabled' => ['enabled' => true, 'form' => []], @@ -225,6 +225,7 @@ class ExportConfigNormalizerTest extends TestCase $expected = [ 'export' => ['form' => [], 'version' => 1], + 'centers' => ['centers' => [10], 'regroupments' => []], 'filters' => [ 'filtersEnabled' => ['enabled' => true, 'form' => [], 'version' => 1], 'filterDisabled' => ['enabled' => false], @@ -238,7 +239,6 @@ class ExportConfigNormalizerTest extends TestCase 'form' => [], 'version' => 1, ], - 'centers' => [10], ]; $exportConfigNormalizer = new ExportConfigNormalizer($exportManager->reveal(), $this->prophesize(CenterRepositoryInterface::class)->reveal()); @@ -280,7 +280,7 @@ class ExportConfigNormalizerTest extends TestCase $centerRepository->find(10)->willReturn($center = new Center()); $serialized = [ - 'centers' => [10], + 'centers' => ['centers' => [10], 'regroupments' => []], 'export' => ['form' => [], 'version' => 1], 'filters' => [ 'filterEnabled' => ['enabled' => true, 'form' => [], 'version' => 1], @@ -309,7 +309,7 @@ class ExportConfigNormalizerTest extends TestCase ], 'pick_formatter' => 'xlsx', 'formatter' => [], - 'centers' => [$center], + 'centers' => ['centers' => [$center], 'regroupments' => []], ]; $exportConfigNormalizer = new ExportConfigNormalizer($exportManager->reveal(), $centerRepository->reveal()); diff --git a/src/Bundle/ChillMainBundle/Tests/Export/ExportGeneratorTest.php b/src/Bundle/ChillMainBundle/Tests/Export/ExportGeneratorTest.php index 3f4d51059..94c29ab90 100644 --- a/src/Bundle/ChillMainBundle/Tests/Export/ExportGeneratorTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Export/ExportGeneratorTest.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\MainBundle\Tests\Export; use Chill\MainBundle\Entity\Center; +use Chill\MainBundle\Entity\Regroupment; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Export\AggregatorInterface; use Chill\MainBundle\Export\DirectExportInterface; @@ -23,6 +24,8 @@ use Chill\MainBundle\Export\ExportManager; use Chill\MainBundle\Export\FilterInterface; use Chill\MainBundle\Export\FormattedExportGeneration; use Chill\MainBundle\Export\FormatterInterface; +use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; +use Chill\MainBundle\Service\Regroupement\CenterRegroupementResolver; use Doctrine\ORM\NativeQuery; use Doctrine\ORM\QueryBuilder; use PHPUnit\Framework\TestCase; @@ -54,7 +57,7 @@ class ExportGeneratorTest extends TestCase ], 'pick_formatter' => 'xlsx', 'formatter' => $formatterData = ['key' => 'form4'], - 'centers' => [$centerA = new Center(), $centerB = new Center()], + 'centers' => ['centers' => [$centerA = new Center()], 'regroupments' => [(new Regroupment())->addCenter($centerB = new Center())]], ]; $user = new User(); @@ -70,11 +73,30 @@ class ExportGeneratorTest extends TestCase // required methods $export->initiateQuery( ['tagada', 'tsointsoin'], - [['center' => $centerA, 'circles' => []], ['center' => $centerB, 'circles' => []]], + Argument::that(function ($arg) use ($centerB, $centerA) { + if (!is_array($arg)) { + return false; + } + if (2 !== count($arg)) { + return false; + } + + foreach ($arg as $item) { + if ([] !== $item['circles']) { + return false; + } + if (!in_array($item['center'], [$centerA, $centerB], true)) { + return false; + } + } + + return true; + }), ['key' => 'form1'], )->shouldBeCalled()->willReturn($query->reveal()); $export->getResult($query->reveal(), $formExportData, Argument::that(static fn (ExportGenerationContext $context) => $context->byUser === $user)) ->shouldBeCalled()->willReturn([['result0' => '0']]); + $export->requiredRole()->willReturn('dummy_role'); $filter->alterQuery($query->reveal(), $formFilterData, Argument::that(static fn (ExportGenerationContext $context) => $context->byUser === $user)) ->shouldBeCalled(); @@ -105,7 +127,10 @@ class ExportGeneratorTest extends TestCase $exportManager->hasAggregator('disabled_aggregator')->willReturn(true); $exportManager->getFormatter('xlsx')->willReturn($formatter->reveal()); - $generator = new ExportGenerator($exportManager->reveal(), $exportConfigNormalizer->reveal(), new NullLogger()); + $authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class); + $authorizationHelper->getReachableCenters($user, 'dummy_role')->willReturn([$centerA, $centerB]); + + $generator = new ExportGenerator($exportManager->reveal(), $exportConfigNormalizer->reveal(), new NullLogger(), $authorizationHelper->reveal(), new CenterRegroupementResolver()); $actual = $generator->generate('dummy', $initialData, $user); @@ -123,7 +148,7 @@ class ExportGeneratorTest extends TestCase 'aggregators' => [], 'pick_formatter' => 'xlsx', 'formatter' => $formatterData = ['key' => 'form4'], - 'centers' => [$centerA = new Center(), $centerB = new Center()], + 'centers' => ['centers' => [$centerA = new Center(), $centerB = new Center()], 'regroupments' => []], ]; $user = new User(); @@ -141,6 +166,7 @@ class ExportGeneratorTest extends TestCase $export->getResult($query->reveal(), $formExportData, Argument::that(static fn (ExportGenerationContext $context) => $context->byUser === $user)) ->shouldBeCalled()->willReturn([['result0' => '0']]); $export->supportsModifiers()->willReturn([]); + $export->requiredRole()->willReturn('dummy_role'); $formatter->generate( [['result0' => '0']], @@ -160,7 +186,10 @@ class ExportGeneratorTest extends TestCase $exportManager->getExport('dummy')->willReturn($export->reveal()); $exportManager->getFormatter('xlsx')->willReturn($formatter->reveal()); - $generator = new ExportGenerator($exportManager->reveal(), $exportConfigNormalizer->reveal(), new NullLogger()); + $authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class); + $authorizationHelper->getReachableCenters($user, 'dummy_role')->willReturn([$centerA, $centerB]); + + $generator = new ExportGenerator($exportManager->reveal(), $exportConfigNormalizer->reveal(), new NullLogger(), $authorizationHelper->reveal(), new CenterRegroupementResolver()); $actual = $generator->generate('dummy', $initialData, $user); diff --git a/src/Bundle/ChillMainBundle/Tests/Services/Regroupement/CenterRegroupementResolverTest.php b/src/Bundle/ChillMainBundle/Tests/Services/Regroupement/CenterRegroupementResolverTest.php new file mode 100644 index 000000000..4f7c2431f --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Services/Regroupement/CenterRegroupementResolverTest.php @@ -0,0 +1,78 @@ +resolveCenters($groups, $centers); + + self::assertEquals(count($expected), count($actual)); + + foreach ($expected as $center) { + self::assertContains($center, $actual); + } + } + + public static function provideData(): iterable + { + $centerA = new Center(); + $centerB = new Center(); + $centerC = new Center(); + $centerD = new Center(); + + $groupA = new Regroupment(); + $groupA->addCenter($centerA)->addCenter($centerB); + + $groupB = new Regroupment(); + $groupB->addCenter($centerA)->addCenter($centerB)->addCenter($centerC); + + yield [ + [$groupA], + [], + [$centerA, $centerB], + ]; + + yield [ + [$groupA, $groupB], + [], + [$centerA, $centerB, $centerC], + ]; + + yield [ + [$groupA, $groupB], + [$centerB, $centerD], + [$centerA, $centerB, $centerC, $centerD], + ]; + } +} diff --git a/src/Bundle/ChillMainBundle/Tests/Services/Regroupement/RegroupementFilteringTest.php b/src/Bundle/ChillMainBundle/Tests/Services/Regroupement/RegroupementFilteringTest.php new file mode 100644 index 000000000..f6976054f --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Services/Regroupement/RegroupementFilteringTest.php @@ -0,0 +1,96 @@ +filterContainsAtLeastOneCenter($groups, $centers); + + self::assertEquals(count($expected), count($actual)); + self::assertTrue(array_is_list($actual)); + + foreach ($expected as $center) { + self::assertContains($center, $actual); + } + } + + public static function provideDataForFilterContainsAtLeastOnCenter(): iterable + { + + $centerA = new Center(); + $centerB = new Center(); + $centerC = new Center(); + $centerD = new Center(); + + $groupA = new Regroupment(); + $groupA->addCenter($centerA)->addCenter($centerB); + + $groupB = new Regroupment(); + $groupB->addCenter($centerA)->addCenter($centerB)->addCenter($centerC); + + $groupC = new Regroupment(); + $groupC->addCenter($centerA)->addCenter($centerD); + + yield [ + [$groupA, $groupB], + [], + [], + ]; + + yield [ + [$groupA, $groupB], + [$centerA, $centerB, $centerC], + [$groupA, $groupB], + ]; + + yield [ + [$groupA, $groupC], + [$centerD], + [$groupC], + ]; + + yield [ + [$groupA], + [$centerB, $centerD], + [$groupA], + ]; + + yield [ + [$groupA], + [new Center()], + [], + ]; + + } +}