mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Compute allowed centers and regroupment at the time of generating the export
This commit is contained in:
parent
128d365a72
commit
e48bec490c
@ -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),
|
||||
|
@ -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<Center> $centers
|
||||
*/
|
||||
public function containsAtLeastOneCenter(array $centers): bool
|
||||
{
|
||||
return array_reduce($centers, fn (bool $carry, Center $center) => $carry || $this->containsCenter($center), false);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
<?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\Export\Exception;
|
||||
|
||||
class ExportGenerationException extends \RuntimeException {}
|
@ -0,0 +1,20 @@
|
||||
<?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\Export\Exception;
|
||||
|
||||
class UnauthorizedGenerationException extends ExportGenerationException
|
||||
{
|
||||
public function __construct(string $message, ?\Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, previous: $previous);
|
||||
}
|
||||
}
|
@ -12,19 +12,22 @@ declare(strict_types=1);
|
||||
namespace Chill\MainBundle\Export;
|
||||
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Regroupment;
|
||||
use Chill\MainBundle\Form\Type\Export\AggregatorType;
|
||||
use Chill\MainBundle\Form\Type\Export\ExportType;
|
||||
use Chill\MainBundle\Form\Type\Export\FilterType;
|
||||
use Chill\MainBundle\Repository\CenterRepositoryInterface;
|
||||
use Chill\MainBundle\Repository\RegroupmentRepository;
|
||||
|
||||
/**
|
||||
* @phpstan-type NormalizedData array{centers: list<int>, export: array{form: array<string, mixed>, version: int}, filters: array<string, array{enabled: boolean, form: array<string, mixed>, version: int}>, aggregators: array<string, array{enabled: boolean, form: array<string, mixed>, version: int}>, pick_formatter: string, formatter: array{form: array<string, mixed>, version: int}}
|
||||
* @phpstan-type NormalizedData array{centers: array{centers: list<int>, regroupments: list<int>}, export: array{form: array<string, mixed>, version: int}, filters: array<string, array{enabled: boolean, form: array<string, mixed>, version: int}>, aggregators: array<string, array{enabled: boolean, form: array<string, mixed>, version: int}>, pick_formatter: string, formatter: array{form: array<string, mixed>, 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)),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -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<Center>
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -1,56 +0,0 @@
|
||||
<?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\Form\DataMapper;
|
||||
|
||||
use Chill\MainBundle\Entity\Regroupment;
|
||||
use Symfony\Component\Form\DataMapperInterface;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
|
||||
final readonly class ExportPickCenterDataMapper implements DataMapperInterface
|
||||
{
|
||||
public function mapDataToForms($viewData, \Traversable $forms): void
|
||||
{
|
||||
if (null === $viewData) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var array<string, FormInterface> $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<string, FormInterface> $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);
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
@ -40,15 +40,15 @@
|
||||
|
||||
<h3 class="m-3">{{ 'Center'|trans }}</h3>
|
||||
|
||||
{{ form_widget(form.centers.center) }}
|
||||
{{ form_widget(form.centers.centers) }}
|
||||
|
||||
<div class="mb-3 mt-3">
|
||||
<input id="toggle-check-all" class="btn btn-misc" type= "button" onclick='uncheckAll(this)' value="{{ 'uncheck all centers'|trans|e('html_attr') }}"/>
|
||||
</div>
|
||||
|
||||
{% if form.centers.regroupment is defined %}
|
||||
{% if form.centers.regroupments is defined %}
|
||||
<h3 class="m-3">{{ 'Pick aggregated centers'|trans }}</h3>
|
||||
{{ form_widget(form.centers.regroupment) }}
|
||||
{{ form_widget(form.centers.regroupments) }}
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
|
@ -0,0 +1,44 @@
|
||||
<?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\Service\Regroupement;
|
||||
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Regroupment;
|
||||
|
||||
class CenterRegroupementResolver
|
||||
{
|
||||
/**
|
||||
* Resolves and returns a unique list of centers by merging those from the provided
|
||||
* groups and the additional centers while eliminating duplicates.
|
||||
*
|
||||
* @param list<Regroupment> $groups
|
||||
* @param list<Center> $centers
|
||||
*
|
||||
* @return list<Center>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<?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\Service\Regroupement;
|
||||
|
||||
use Chill\MainBundle\Entity\Regroupment;
|
||||
|
||||
/**
|
||||
* Class RegroupementFiltering.
|
||||
*
|
||||
* Provides methods to filter and manage groups based on specific criteria.
|
||||
*/
|
||||
class RegroupementFiltering
|
||||
{
|
||||
/**
|
||||
* Filters the provided groups and returns only those that contain at least one of the specified centers.
|
||||
*
|
||||
* @param array $groups an array of groups to filter
|
||||
* @param array $centers an array of centers to check against the groups
|
||||
*
|
||||
* @return array an array of filtered groups containing at least one of the specified centers
|
||||
*/
|
||||
public function filterContainsAtLeastOneCenter(array $groups, array $centers): array
|
||||
{
|
||||
return array_values(
|
||||
array_filter($groups, static fn (Regroupment $group) => $group->containsAtLeastOneCenter($centers)),
|
||||
);
|
||||
}
|
||||
}
|
@ -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());
|
||||
|
@ -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);
|
||||
|
||||
|
@ -0,0 +1,78 @@
|
||||
<?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\Services\Regroupement;
|
||||
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Regroupment;
|
||||
use Chill\MainBundle\Service\Regroupement\CenterRegroupementResolver;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class CenterRegroupementResolverTest extends TestCase
|
||||
{
|
||||
private static CenterRegroupementResolver $resolver;
|
||||
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
self::$resolver = new CenterRegroupementResolver();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideData
|
||||
*/
|
||||
public function testResolveCenter(array $groups, array $centers, array $expected): void
|
||||
{
|
||||
$actual = self::$resolver->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],
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
<?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\Services\Regroupement;
|
||||
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Regroupment;
|
||||
use Chill\MainBundle\Service\Regroupement\RegroupementFiltering;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class RegroupementFilteringTest extends TestCase
|
||||
{
|
||||
private static RegroupementFiltering $regroupementFiltering;
|
||||
|
||||
public static function setUpBeforeClass(): void
|
||||
{
|
||||
self::$regroupementFiltering = new RegroupementFiltering();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideDataForFilterContainsAtLeastOnCenter
|
||||
*/
|
||||
public function testFilterContainsAtLeastOnCenter(array $groups, array $centers, array $expected): void
|
||||
{
|
||||
$actual = self::$regroupementFiltering->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()],
|
||||
[],
|
||||
];
|
||||
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user