mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch '343-social_issue_action_export' into 'master'
Resolve "Permettre de télécharger la liste des problématiques et la liste des actions en CSV" Closes #343 See merge request Chill-Projet/chill-bundles!785
This commit is contained in:
commit
8de63de6d6
6
.changes/unreleased/Feature-20250130-120459.yaml
Normal file
6
.changes/unreleased/Feature-20250130-120459.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: Add possibility to export a csv with all social issues and social actions
|
||||||
|
time: 2025-01-30T12:04:59.754998541+01:00
|
||||||
|
custom:
|
||||||
|
Issue: "343"
|
||||||
|
SchemaChange: No schema change
|
@ -735,6 +735,25 @@ export:
|
|||||||
steps: Escaliers
|
steps: Escaliers
|
||||||
_lat: Latitude
|
_lat: Latitude
|
||||||
_lon: Longitude
|
_lon: Longitude
|
||||||
|
social_action_list:
|
||||||
|
id: Identifiant de l'action
|
||||||
|
social_issue_id: Identifiant de la problématique sociale
|
||||||
|
social_issue: Problématique sociale
|
||||||
|
social_issue_ordering: Ordre de la problématique sociale
|
||||||
|
action_label: Action d'accompagnement
|
||||||
|
action_ordering: Ordre
|
||||||
|
goal_label: Objectif
|
||||||
|
goal_id: Identifiant de l'objectif
|
||||||
|
goal_result_label: Résultat
|
||||||
|
goal_result_id: Identifiant du résultat
|
||||||
|
result_without_goal_label: Résultat (sans objectif)
|
||||||
|
result_without_goal_id: Identifiant du résultat (sans objectif)
|
||||||
|
evaluation_title: Évaluation
|
||||||
|
evaluation_id: Identifiant de l'évaluation
|
||||||
|
evaluation_url: Adresse URL externe (évaluation)
|
||||||
|
evaluation_delay_month: Délai de notification (mois)
|
||||||
|
evaluation_delay_week: Délai de notification (semaine)
|
||||||
|
evaluation_delay_day: Délai de notification (jours)
|
||||||
|
|
||||||
rolling_date:
|
rolling_date:
|
||||||
year_previous_start: Début de l'année précédente
|
year_previous_start: Début de l'année précédente
|
||||||
|
@ -0,0 +1,66 @@
|
|||||||
|
<?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\PersonBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository;
|
||||||
|
use Chill\PersonBundle\Service\SocialWork\SocialActionCSVExportService;
|
||||||
|
use League\Csv\CannotInsertRecord;
|
||||||
|
use League\Csv\Exception;
|
||||||
|
use League\Csv\UnavailableStream;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
|
class SocialActionCSVExportController extends AbstractController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly SocialActionRepository $socialActionRepository,
|
||||||
|
private readonly Security $security,
|
||||||
|
private readonly SocialActionCSVExportService $socialActionCSVExportService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws UnavailableStream
|
||||||
|
* @throws CannotInsertRecord
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
#[Route(path: '/{_locale}/admin/social-work/social-action/export/list.{_format}', name: 'chill_person_social_action_export_list', requirements: ['_format' => 'csv'])]
|
||||||
|
public function socialActionList(Request $request, string $_format = 'csv'): StreamedResponse
|
||||||
|
{
|
||||||
|
if (!$this->security->isGranted('ROLE_ADMIN')) {
|
||||||
|
throw new AccessDeniedHttpException('Only ROLE_ADMIN can export this list');
|
||||||
|
}
|
||||||
|
|
||||||
|
$actions = $this->socialActionRepository->findAllOrdered();
|
||||||
|
|
||||||
|
$csv = $this->socialActionCSVExportService->generateCsv($actions);
|
||||||
|
|
||||||
|
return new StreamedResponse(
|
||||||
|
function () use ($csv) {
|
||||||
|
foreach ($csv->chunk(1024) as $chunk) {
|
||||||
|
echo $chunk;
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Response::HTTP_OK,
|
||||||
|
[
|
||||||
|
'Content-Encoding' => 'none',
|
||||||
|
'Content-Type' => 'text/csv; charset=UTF-8',
|
||||||
|
'Content-Disposition' => 'attachment; filename=results.csv',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
<?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\PersonBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
|
||||||
|
use Chill\PersonBundle\Service\SocialWork\SocialIssueCSVExportService;
|
||||||
|
use League\Csv\CannotInsertRecord;
|
||||||
|
use League\Csv\Exception;
|
||||||
|
use League\Csv\UnavailableStream;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
|
class SocialIssueCSVExportController extends AbstractController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly SocialIssueRepository $socialIssueRepository,
|
||||||
|
private readonly Security $security,
|
||||||
|
private readonly SocialIssueCSVExportService $socialIssueCSVExportService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws UnavailableStream
|
||||||
|
* @throws CannotInsertRecord
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
#[Route(path: '/{_locale}/admin/social-work/social-issue/export/list.{_format}', name: 'chill_person_social_issue_export_list', requirements: ['_format' => 'csv'])]
|
||||||
|
public function socialIssueList(Request $request, string $_format = 'csv'): StreamedResponse
|
||||||
|
{
|
||||||
|
if (!$this->security->isGranted('ROLE_ADMIN')) {
|
||||||
|
throw new AccessDeniedHttpException('Only ROLE_ADMIN can export this list');
|
||||||
|
}
|
||||||
|
|
||||||
|
$socialIssues = $this->socialIssueRepository->findAllOrdered();
|
||||||
|
|
||||||
|
$csv = $this->socialIssueCSVExportService->generateCsv($socialIssues);
|
||||||
|
|
||||||
|
return new StreamedResponse(
|
||||||
|
function () use ($csv) {
|
||||||
|
foreach ($csv->chunk(1024) as $chunk) {
|
||||||
|
echo $chunk;
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Response::HTTP_OK,
|
||||||
|
[
|
||||||
|
'Content-Encoding' => 'none',
|
||||||
|
'Content-Type' => 'text/csv; charset=UTF-8',
|
||||||
|
'Content-Disposition' => 'attachment; users.csv',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,149 +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\PersonBundle\Controller;
|
|
||||||
|
|
||||||
use Chill\PersonBundle\Repository\SocialWork\SocialActionRepository;
|
|
||||||
use Chill\PersonBundle\Repository\SocialWork\SocialIssueRepository;
|
|
||||||
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
|
|
||||||
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
|
|
||||||
use League\Csv\CannotInsertRecord;
|
|
||||||
use League\Csv\Exception;
|
|
||||||
use League\Csv\UnavailableStream;
|
|
||||||
use League\Csv\Writer;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
||||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
|
||||||
use Symfony\Component\Security\Core\Security;
|
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
||||||
|
|
||||||
class SocialWorkExportController extends AbstractController
|
|
||||||
{
|
|
||||||
public function __construct(
|
|
||||||
private readonly SocialIssueRepository $socialIssueRepository,
|
|
||||||
private readonly SocialActionRepository $socialActionRepository,
|
|
||||||
private readonly Security $security,
|
|
||||||
private readonly TranslatorInterface $translator,
|
|
||||||
private readonly SocialIssueRender $socialIssueRender,
|
|
||||||
private readonly SocialActionRender $socialActionRender,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws UnavailableStream
|
|
||||||
* @throws CannotInsertRecord
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
#[Route(path: '/{_locale}/admin/social-work/social-issue/export/list.{_format}', name: 'chill_person_social_issue_export_list', requirements: ['_format' => 'csv'])]
|
|
||||||
public function socialIssueList(Request $request, string $_format = 'csv'): StreamedResponse
|
|
||||||
{
|
|
||||||
if (!$this->security->isGranted('ROLE_ADMIN')) {
|
|
||||||
throw new AccessDeniedHttpException('Only ROLE_ADMIN can export this list');
|
|
||||||
}
|
|
||||||
|
|
||||||
$socialIssues = $this->socialIssueRepository->findAll();
|
|
||||||
|
|
||||||
$socialIssues = array_map(fn ($issue) => [
|
|
||||||
'id' => $issue->getId(),
|
|
||||||
'title' => $this->socialIssueRender->renderString($issue, []),
|
|
||||||
'ordering' => $issue->getOrdering(),
|
|
||||||
'desactivationDate' => $issue->getDesactivationDate(),
|
|
||||||
], $socialIssues);
|
|
||||||
|
|
||||||
$csv = Writer::createFromPath('php://temp', 'r+');
|
|
||||||
$csv->insertOne(
|
|
||||||
array_map(
|
|
||||||
fn (string $e) => $this->translator->trans($e),
|
|
||||||
[
|
|
||||||
'Id',
|
|
||||||
'Title',
|
|
||||||
'Ordering',
|
|
||||||
'goal.desactivationDate',
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$csv->addFormatter(fn (array $row) => null !== ($row['desactivationDate'] ?? null) ? array_merge($row, ['desactivationDate' => $row['desactivationDate']->format('Y-m-d')]) : $row);
|
|
||||||
$csv->insertAll($socialIssues);
|
|
||||||
|
|
||||||
return new StreamedResponse(
|
|
||||||
function () use ($csv) {
|
|
||||||
foreach ($csv->chunk(1024) as $chunk) {
|
|
||||||
echo $chunk;
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Response::HTTP_OK,
|
|
||||||
[
|
|
||||||
'Content-Encoding' => 'none',
|
|
||||||
'Content-Type' => 'text/csv; charset=UTF-8',
|
|
||||||
'Content-Disposition' => 'attachment; users.csv',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws UnavailableStream
|
|
||||||
* @throws CannotInsertRecord
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
#[Route(path: '/{_locale}/admin/social-work/social-action/export/list.{_format}', name: 'chill_person_social_action_export_list', requirements: ['_format' => 'csv'])]
|
|
||||||
public function socialActionList(Request $request, string $_format = 'csv'): StreamedResponse
|
|
||||||
{
|
|
||||||
if (!$this->security->isGranted('ROLE_ADMIN')) {
|
|
||||||
throw new AccessDeniedHttpException('Only ROLE_ADMIN can export this list');
|
|
||||||
}
|
|
||||||
|
|
||||||
$socialActions = $this->socialActionRepository->findAll();
|
|
||||||
|
|
||||||
$socialActions = array_map(fn ($action) => [
|
|
||||||
'id' => $action->getId(),
|
|
||||||
'title' => $this->socialActionRender->renderString($action, []),
|
|
||||||
'desactivationDate' => $action->getDesactivationDate(),
|
|
||||||
'socialIssue' => $this->socialIssueRender->renderString($action->getIssue(), []),
|
|
||||||
'ordering' => $action->getOrdering(),
|
|
||||||
], $socialActions);
|
|
||||||
|
|
||||||
$csv = Writer::createFromPath('php://temp', 'r+');
|
|
||||||
$csv->insertOne(
|
|
||||||
array_map(
|
|
||||||
fn (string $e) => $this->translator->trans($e),
|
|
||||||
[
|
|
||||||
'Id',
|
|
||||||
'Title',
|
|
||||||
'goal.desactivationDate',
|
|
||||||
'Social issue',
|
|
||||||
'Ordering',
|
|
||||||
]
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$csv->addFormatter(fn (array $row) => null !== ($row['desactivationDate'] ?? null) ? array_merge($row, ['desactivationDate' => $row['desactivationDate']->format('Y-m-d')]) : $row);
|
|
||||||
$csv->insertAll($socialActions);
|
|
||||||
|
|
||||||
return new StreamedResponse(
|
|
||||||
function () use ($csv) {
|
|
||||||
foreach ($csv->chunk(1024) as $chunk) {
|
|
||||||
echo $chunk;
|
|
||||||
flush();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Response::HTTP_OK,
|
|
||||||
[
|
|
||||||
'Content-Encoding' => 'none',
|
|
||||||
'Content-Type' => 'text/csv; charset=UTF-8',
|
|
||||||
'Content-Disposition' => 'attachment; users.csv',
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -44,6 +44,14 @@ final readonly class SocialActionRepository implements ObjectRepository
|
|||||||
return $this->repository->findAll();
|
return $this->repository->findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findAllOrdered(): array
|
||||||
|
{
|
||||||
|
return $this->repository->createQueryBuilder('si')
|
||||||
|
->orderBy('si.ordering', 'ASC')
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array|SocialAction[]
|
* @return array|SocialAction[]
|
||||||
*/
|
*/
|
||||||
|
@ -39,6 +39,14 @@ final readonly class SocialIssueRepository implements ObjectRepository
|
|||||||
return $this->repository->findAll();
|
return $this->repository->findAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findAllOrdered(): array
|
||||||
|
{
|
||||||
|
return $this->repository->createQueryBuilder('si')
|
||||||
|
->orderBy('si.ordering', 'ASC')
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array|SocialIssue[]
|
* @return array|SocialIssue[]
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,104 @@
|
|||||||
|
<?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\PersonBundle\Service\SocialWork;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\SocialWork\Evaluation;
|
||||||
|
use Chill\PersonBundle\Entity\SocialWork\Goal;
|
||||||
|
use Chill\PersonBundle\Entity\SocialWork\Result;
|
||||||
|
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||||
|
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
|
||||||
|
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use League\Csv\Writer;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
final readonly class SocialActionCSVExportService
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private SocialIssueRender $socialIssueRender,
|
||||||
|
private SocialActionRender $socialActionRender,
|
||||||
|
private TranslatableStringHelperInterface $stringHelper,
|
||||||
|
private TranslatorInterface $translator,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<SocialAction> $actions
|
||||||
|
*/
|
||||||
|
public function generateCsv(array $actions): Writer
|
||||||
|
{
|
||||||
|
// CSV headers
|
||||||
|
$headers = array_map(
|
||||||
|
fn (string $tr) => $this->translator->trans('export.social_action_list.'.$tr),
|
||||||
|
array_keys($this->formatRow(new SocialAction()))
|
||||||
|
);
|
||||||
|
|
||||||
|
$csv = Writer::createFromPath('php://temp', 'w+');
|
||||||
|
$csv->insertOne($headers);
|
||||||
|
|
||||||
|
foreach ($actions as $action) {
|
||||||
|
if ($action->getGoals()->isEmpty() && $action->getResults()->isEmpty() && $action->getEvaluations()->isEmpty()) {
|
||||||
|
$csv->insertOne($this->formatRow($action));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($action->getGoals() as $goal) {
|
||||||
|
if ($goal->getResults()->isEmpty()) {
|
||||||
|
$csv->insertOne($this->formatRow($action, $goal));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($goal->getResults() as $goalResult) {
|
||||||
|
$csv->insertOne($this->formatRow($action, $goal, $goalResult));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($action->getResults() as $result) {
|
||||||
|
if ($result->getGoals()->isEmpty()) {
|
||||||
|
$csv->insertOne($this->formatRow($action, null, null, $result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($action->getEvaluations() as $evaluation) {
|
||||||
|
$csv->insertOne($this->formatRow($action, evaluation: $evaluation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $csv;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function formatRow(
|
||||||
|
SocialAction $action,
|
||||||
|
?Goal $goal = null,
|
||||||
|
?Result $goalResult = null,
|
||||||
|
?Result $resultWithoutGoal = null,
|
||||||
|
?Evaluation $evaluation = null,
|
||||||
|
): array {
|
||||||
|
return [
|
||||||
|
'action_id' => $action->getId(),
|
||||||
|
'social_issue_id' => $action->getIssue()?->getId(),
|
||||||
|
'problematique_label' => null !== $action->getIssue() ? $this->socialIssueRender->renderString($action->getIssue(), []) : null,
|
||||||
|
'social_issue_ordering' => null !== $action->getIssue() ? $action->getIssue()->getOrdering() : null,
|
||||||
|
'action_label' => $this->socialActionRender->renderString($action, []),
|
||||||
|
'action_ordering' => $action->getOrdering(),
|
||||||
|
'goal_label' => null !== $goal ? $this->stringHelper->localize($goal->getTitle()) : null,
|
||||||
|
'goal_id' => $goal?->getId(),
|
||||||
|
'goal_result_label' => null !== $goalResult ? $this->stringHelper->localize($goalResult->getTitle()) : null,
|
||||||
|
'goal_result_id' => $goalResult?->getId(),
|
||||||
|
'result_without_goal_label' => null !== $resultWithoutGoal ? $this->stringHelper->localize($resultWithoutGoal->getTitle()) : null,
|
||||||
|
'result_without_goal_id' => $resultWithoutGoal?->getId(),
|
||||||
|
'evaluation_title' => null !== $evaluation ? $this->stringHelper->localize($evaluation->getTitle()) : null,
|
||||||
|
'evaluation_id' => $evaluation?->getId(),
|
||||||
|
'evaluation_url' => $evaluation?->getUrl(),
|
||||||
|
'evaluation_delay_month' => $evaluation?->getDelay()?->format('%m'),
|
||||||
|
'evaluation_delay_week' => $evaluation?->getDelay()?->format('%w'),
|
||||||
|
'evaluation_delay_day' => $evaluation?->getDelay()?->format('%d'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
<?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\PersonBundle\Service\SocialWork;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
||||||
|
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use League\Csv\CannotInsertRecord;
|
||||||
|
use League\Csv\Exception;
|
||||||
|
use League\Csv\UnavailableStream;
|
||||||
|
use League\Csv\Writer;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
readonly class SocialIssueCSVExportService
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private SocialIssueRender $socialIssueRender,
|
||||||
|
private TranslatableStringHelperInterface $stringHelper,
|
||||||
|
private TranslatorInterface $translator,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws UnavailableStream
|
||||||
|
* @throws CannotInsertRecord
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function generateCsv(array $issues): Writer
|
||||||
|
{
|
||||||
|
// CSV headers
|
||||||
|
$csv = Writer::createFromPath('php://temp', 'r+');
|
||||||
|
$csv->insertOne(
|
||||||
|
array_map(
|
||||||
|
fn (string $e) => $this->translator->trans($e),
|
||||||
|
[
|
||||||
|
'Id',
|
||||||
|
'Label',
|
||||||
|
'Social issue',
|
||||||
|
'socialIssue.isParent?',
|
||||||
|
'socialIssue.Parent id',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($issues as $issue) {
|
||||||
|
$csv->insertOne($this->formatRow($issue));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return $csv;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function formatRow(
|
||||||
|
SocialIssue $issue,
|
||||||
|
): array {
|
||||||
|
return
|
||||||
|
[
|
||||||
|
'id' => $issue->getId(),
|
||||||
|
'label' => $this->stringHelper->localize($issue->getTitle()),
|
||||||
|
'title' => $this->socialIssueRender->renderString($issue, []),
|
||||||
|
'isParent' => $issue->hasChildren() ? 'X' : '',
|
||||||
|
'parent_id' => null !== $issue->getParent() ? $issue->getParent()->getId() : '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,7 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||||||
/**
|
/**
|
||||||
* @implements ChillEntityRenderInterface<SocialIssue>
|
* @implements ChillEntityRenderInterface<SocialIssue>
|
||||||
*/
|
*/
|
||||||
final readonly class SocialIssueRender implements ChillEntityRenderInterface
|
class SocialIssueRender implements ChillEntityRenderInterface
|
||||||
{
|
{
|
||||||
public const AND_CHILDREN_MENTION = 'show_and_children_mention';
|
public const AND_CHILDREN_MENTION = 'show_and_children_mention';
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ final readonly class SocialIssueRender implements ChillEntityRenderInterface
|
|||||||
*/
|
*/
|
||||||
public const SHOW_AND_CHILDREN = 'show_and_children';
|
public const SHOW_AND_CHILDREN = 'show_and_children';
|
||||||
|
|
||||||
public function __construct(private TranslatableStringHelper $translatableStringHelper, private \Twig\Environment $engine, private TranslatorInterface $translator) {}
|
public function __construct(private readonly TranslatableStringHelper $translatableStringHelper, private readonly \Twig\Environment $engine, private readonly TranslatorInterface $translator) {}
|
||||||
|
|
||||||
public function renderBox($socialIssue, array $options): string
|
public function renderBox($socialIssue, array $options): string
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
<?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 Bundle\ChillPersonBundle\Tests\Exporters;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use Chill\PersonBundle\Entity\SocialWork\Goal;
|
||||||
|
use Chill\PersonBundle\Entity\SocialWork\Result;
|
||||||
|
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
|
||||||
|
use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
|
||||||
|
use Chill\PersonBundle\Service\SocialWork\SocialActionCSVExportService;
|
||||||
|
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
|
||||||
|
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class SocialActionCsvExporterTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testGenerateCsv(): void
|
||||||
|
{
|
||||||
|
$translator = $this->createMock(TranslatorInterface::class);
|
||||||
|
$translator->method('trans')->willReturnArgument(0);
|
||||||
|
$socialIssueRender = $this->createMock(SocialIssueRender::class);
|
||||||
|
$socialIssueRender->method('renderString')->willReturnCallback(static fn (SocialIssue $socialIssue) => $socialIssue->getTitle()['fr'] ?? '');
|
||||||
|
$socialActionRender = $this->createMock(SocialActionRender::class);
|
||||||
|
$socialActionRender->method('renderString')->willReturnCallback(static fn (SocialAction $socialAction) => $socialAction->getTitle()['fr'] ?? '');
|
||||||
|
$stringHelper = $this->createMock(TranslatableStringHelperInterface::class);
|
||||||
|
$stringHelper->method('localize')
|
||||||
|
->willReturnCallback(static fn (array $messages) => $messages['fr'] ?? 'not found');
|
||||||
|
|
||||||
|
$exporter = new SocialActionCSVExportService($socialIssueRender, $socialActionRender, $stringHelper, $translator);
|
||||||
|
|
||||||
|
// Mock social issue
|
||||||
|
|
||||||
|
// Création d'une instance réelle de SocialIssue
|
||||||
|
$socialIssue = new SocialIssue();
|
||||||
|
$socialIssue->setTitle(['fr' => 'Issue Title']); // Exemple de définition d'une propriété
|
||||||
|
|
||||||
|
// Création d'une instance réelle de SocialAction sans objectifs ni résultats
|
||||||
|
$actionWithoutGoalsOrResults = new SocialAction();
|
||||||
|
$actionWithoutGoalsOrResults->setIssue($socialIssue);
|
||||||
|
$actionWithoutGoalsOrResults->setTitle(['fr' => 'Action without goals or results']);
|
||||||
|
|
||||||
|
// Création d'une instance réelle de SocialAction avec des objectifs et des résultats
|
||||||
|
$goalWithResult = new Goal();
|
||||||
|
$resultWithAction = new Result();
|
||||||
|
$goalWithResult->addResult($resultWithAction);
|
||||||
|
|
||||||
|
$actionWithGoalsAndResults = new SocialAction();
|
||||||
|
$actionWithGoalsAndResults->setIssue($socialIssue);
|
||||||
|
$actionWithGoalsAndResults->setTitle(['fr' => 'Action with goals and results']);
|
||||||
|
$actionWithGoalsAndResults->addGoal($goalWithResult);
|
||||||
|
|
||||||
|
// Création d'une instance réelle de SocialAction avec des objectifs mais sans résultats
|
||||||
|
$goalWithoutResult = new Goal();
|
||||||
|
$actionWithGoalsNoResults = new SocialAction();
|
||||||
|
$actionWithGoalsNoResults->setIssue($socialIssue);
|
||||||
|
$actionWithGoalsNoResults->setTitle(['fr' => 'Action with goals and no results']);
|
||||||
|
$actionWithGoalsNoResults->addGoal($goalWithoutResult);
|
||||||
|
|
||||||
|
// Création d'une instance réelle de SocialAction avec des résultats mais sans objectifs
|
||||||
|
$resultWithNoAction = new Result();
|
||||||
|
$resultWithNoAction->setTitle(['fr' => 'Result without objectives']);
|
||||||
|
$actionWithResultsNoGoals = new SocialAction();
|
||||||
|
$actionWithResultsNoGoals->setIssue($socialIssue);
|
||||||
|
$actionWithResultsNoGoals->setTitle(['fr' => 'Action with results and no goals']);
|
||||||
|
$actionWithResultsNoGoals->addResult($resultWithNoAction);
|
||||||
|
|
||||||
|
// generate
|
||||||
|
$csv = $exporter->generateCsv([$actionWithGoalsAndResults, $actionWithoutGoalsOrResults,
|
||||||
|
$actionWithGoalsNoResults, $actionWithResultsNoGoals]);
|
||||||
|
$content = $csv->toString();
|
||||||
|
|
||||||
|
// Assert CSV contains expected values
|
||||||
|
$this->assertStringContainsString('Action without goals or results', $content);
|
||||||
|
$this->assertStringContainsString('Action with goals and results', $content);
|
||||||
|
$this->assertStringContainsString('Action with goals and no results', $content);
|
||||||
|
$this->assertStringContainsString('Action with results and no goals', $content);
|
||||||
|
|
||||||
|
self::assertEquals(<<<'CSV'
|
||||||
|
export.social_action_list.action_id,export.social_action_list.social_issue_id,export.social_action_list.problematique_label,export.social_action_list.social_issue_ordering,export.social_action_list.action_label,export.social_action_list.action_ordering,export.social_action_list.goal_label,export.social_action_list.goal_id,export.social_action_list.goal_result_label,export.social_action_list.goal_result_id,export.social_action_list.result_without_goal_label,export.social_action_list.result_without_goal_id,export.social_action_list.evaluation_title,export.social_action_list.evaluation_id,export.social_action_list.evaluation_url,export.social_action_list.evaluation_delay_month,export.social_action_list.evaluation_delay_week,export.social_action_list.evaluation_delay_day
|
||||||
|
,,"Issue Title",0,"Action with goals and results",0,"not found",,"not found",,,,,,,,,
|
||||||
|
,,"Issue Title",0,"Action without goals or results",0,,,,,,,,,,,,
|
||||||
|
,,"Issue Title",0,"Action with goals and no results",0,"not found",,,,,,,,,,,
|
||||||
|
,,"Issue Title",0,"Action with results and no goals",0,,,,,"Result without objectives",,,,,,,
|
||||||
|
|
||||||
|
CSV, $content);
|
||||||
|
}
|
||||||
|
}
|
@ -71,6 +71,9 @@ services:
|
|||||||
Chill\PersonBundle\Controller\PersonSignatureController:
|
Chill\PersonBundle\Controller\PersonSignatureController:
|
||||||
tags: [ 'controller.service_arguments' ]
|
tags: [ 'controller.service_arguments' ]
|
||||||
|
|
||||||
Chill\PersonBundle\Controller\SocialWorkExportController:
|
Chill\PersonBundle\Controller\SocialIssueCSVExportController:
|
||||||
|
tags: [ 'controller.service_arguments' ]
|
||||||
|
|
||||||
|
Chill\PersonBundle\Controller\SocialActionCSVExportController:
|
||||||
tags: [ 'controller.service_arguments' ]
|
tags: [ 'controller.service_arguments' ]
|
||||||
|
|
||||||
|
@ -755,6 +755,11 @@ socialAction:
|
|||||||
defaultNotificationDelay: Délai de notification par défaut
|
defaultNotificationDelay: Délai de notification par défaut
|
||||||
socialIssue: Problématique sociale
|
socialIssue: Problématique sociale
|
||||||
|
|
||||||
|
socialIssue:
|
||||||
|
isParent?: Parent?
|
||||||
|
Parent id: Identifiant du parent
|
||||||
|
|
||||||
|
|
||||||
household_id: Identifiant du ménage
|
household_id: Identifiant du ménage
|
||||||
household:
|
household:
|
||||||
allowHolder: Peut être titulaire
|
allowHolder: Peut être titulaire
|
||||||
|
Loading…
x
Reference in New Issue
Block a user