mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
[export] add a filter and aggregator on activities: filter/group by persons taking part to the activity
This commit is contained in:
parent
a4edb34668
commit
11fb9bcd0b
6
.changes/unreleased/Feature-20231018-160235.yaml
Normal file
6
.changes/unreleased/Feature-20231018-160235.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
kind: Feature
|
||||||
|
body: '[export] add a filter and aggregator on activites: group/filter activities
|
||||||
|
by people participating to the exchange'
|
||||||
|
time: 2023-10-18T16:02:35.99265091+02:00
|
||||||
|
custom:
|
||||||
|
Issue: "172"
|
@ -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\ActivityBundle\Export\Aggregator;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Export\Declarations;
|
||||||
|
use Chill\ActivityBundle\Tests\Export\Aggregator\PersonsAggregatorTest;
|
||||||
|
use Chill\MainBundle\Export\AggregatorInterface;
|
||||||
|
use Chill\PersonBundle\Export\Helper\LabelPersonHelper;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see PersonsAggregatorTest
|
||||||
|
*/
|
||||||
|
final readonly class PersonsAggregator implements AggregatorInterface
|
||||||
|
{
|
||||||
|
private const PREFIX = 'act_persons_agg';
|
||||||
|
|
||||||
|
public function __construct(private LabelPersonHelper $labelPersonHelper) {}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
// nothing to add here
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormDefaultData(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLabels($key, array $values, mixed $data)
|
||||||
|
{
|
||||||
|
if ($key !== self::PREFIX.'_pid') {
|
||||||
|
throw new \UnexpectedValueException('this key should not be handled: '.$key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->labelPersonHelper->getLabel($key, $values, 'export.aggregator.activity.by_persons.Persons');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryKeys($data)
|
||||||
|
{
|
||||||
|
return [self::PREFIX.'_pid'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle()
|
||||||
|
{
|
||||||
|
return 'export.aggregator.activity.by_persons.Group activity by persons';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data)
|
||||||
|
{
|
||||||
|
$p = self::PREFIX;
|
||||||
|
|
||||||
|
$qb
|
||||||
|
->leftJoin('activity.persons', "{$p}_p")
|
||||||
|
->addSelect("{$p}_p.id AS {$p}_pid")
|
||||||
|
->addGroupBy("{$p}_pid");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyOn()
|
||||||
|
{
|
||||||
|
return Declarations::ACTIVITY;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
<?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\ActivityBundle\Export\Filter;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Export\Declarations;
|
||||||
|
use Chill\ActivityBundle\Tests\Export\Filter\PersonsFilterTest;
|
||||||
|
use Chill\MainBundle\Export\FilterInterface;
|
||||||
|
use Chill\PersonBundle\Form\Type\PickPersonDynamicType;
|
||||||
|
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see PersonsFilterTest
|
||||||
|
*/
|
||||||
|
final readonly class PersonsFilter implements FilterInterface
|
||||||
|
{
|
||||||
|
private const PREFIX = 'act_persons_filter';
|
||||||
|
|
||||||
|
public function __construct(private PersonRenderInterface $personRender) {}
|
||||||
|
|
||||||
|
public function addRole(): ?string
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function alterQuery(QueryBuilder $qb, $data)
|
||||||
|
{
|
||||||
|
$p = self::PREFIX;
|
||||||
|
|
||||||
|
$orX = $qb->expr()->orX();
|
||||||
|
|
||||||
|
foreach (array_values($data['accepted_persons']) as $key => $person) {
|
||||||
|
$orX->add($qb->expr()->isMemberOf(":{$p}_p_{$key}", 'activity.persons'));
|
||||||
|
$qb->setParameter(":{$p}_p_{$key}", $person);
|
||||||
|
}
|
||||||
|
|
||||||
|
$qb->andWhere($orX);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyOn()
|
||||||
|
{
|
||||||
|
return Declarations::ACTIVITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder)
|
||||||
|
{
|
||||||
|
$builder->add('accepted_persons', PickPersonDynamicType::class, [
|
||||||
|
'multiple' => true,
|
||||||
|
'label' => 'export.filter.activity.by_persons.persons taking part on the activity',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormDefaultData(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'accepted_persons' => [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function describeAction($data, $format = 'string')
|
||||||
|
{
|
||||||
|
$users = [];
|
||||||
|
|
||||||
|
foreach ($data['accepted_persons'] as $u) {
|
||||||
|
$users[] = $this->personRender->renderString($u, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['export.filter.activity.by_persons.Filtered activity by persons: only %persons%', [
|
||||||
|
'%persons%' => implode(', ', $users),
|
||||||
|
]];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return 'export.filter.activity.by_persons.Filter activity by persons';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
<?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\ActivityBundle\Tests\Export\Aggregator;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Chill\ActivityBundle\Export\Aggregator\PersonsAggregator;
|
||||||
|
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||||
|
use Chill\PersonBundle\Export\Helper\LabelPersonHelper;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class PersonsAggregatorTest extends AbstractAggregatorTest
|
||||||
|
{
|
||||||
|
private LabelPersonHelper $labelPersonHelper;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
self::bootKernel();
|
||||||
|
$this->labelPersonHelper = self::$container->get(LabelPersonHelper::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAggregator()
|
||||||
|
{
|
||||||
|
return new PersonsAggregator($this->labelPersonHelper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormData()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryBuilders()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
|
||||||
|
$em = self::$container->get(EntityManagerInterface::class);
|
||||||
|
|
||||||
|
return [
|
||||||
|
$em->createQueryBuilder()
|
||||||
|
->select('count(activity.id)')
|
||||||
|
->from(Activity::class, 'activity'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
<?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\ActivityBundle\Tests\Export\Filter;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Chill\ActivityBundle\Export\Filter\PersonsFilter;
|
||||||
|
use Chill\MainBundle\Test\Export\AbstractFilterTest;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
use Chill\PersonBundle\Templating\Entity\PersonRenderInterface;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class PersonsFilterTest extends AbstractFilterTest
|
||||||
|
{
|
||||||
|
private PersonRenderInterface $personRender;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
self::bootKernel();
|
||||||
|
$this->personRender = self::$container->get(PersonRenderInterface::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFilter()
|
||||||
|
{
|
||||||
|
return new PersonsFilter($this->personRender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormData()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$em = self::$container->get(EntityManagerInterface::class);
|
||||||
|
|
||||||
|
$persons = $em->createQuery('SELECT p FROM '.Person::class.' p ')
|
||||||
|
->setMaxResults(2)
|
||||||
|
->getResult();
|
||||||
|
|
||||||
|
self::ensureKernelShutdown();
|
||||||
|
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'accepted_persons' => $persons,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQueryBuilders()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
|
||||||
|
$em = self::$container->get(EntityManagerInterface::class);
|
||||||
|
|
||||||
|
yield $em->createQueryBuilder()
|
||||||
|
->select('count(activity.id)')
|
||||||
|
->from(Activity::class, 'activity');
|
||||||
|
|
||||||
|
self::ensureKernelShutdown();
|
||||||
|
}
|
||||||
|
}
|
@ -200,3 +200,11 @@ services:
|
|||||||
Chill\ActivityBundle\Export\Aggregator\SentReceivedAggregator:
|
Chill\ActivityBundle\Export\Aggregator\SentReceivedAggregator:
|
||||||
tags:
|
tags:
|
||||||
- { name: chill.export_aggregator, alias: activity_sentreceived_aggregator }
|
- { name: chill.export_aggregator, alias: activity_sentreceived_aggregator }
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Export\Filter\PersonsFilter:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_filter, alias: activity_by_persons_filter }
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Export\Aggregator\PersonsAggregator:
|
||||||
|
tags:
|
||||||
|
- { name: chill.export_aggregator, alias: activity_by_persons_aggregator }
|
||||||
|
@ -377,6 +377,10 @@ export:
|
|||||||
by_creator_scope:
|
by_creator_scope:
|
||||||
Filter activity by user scope: Filtrer les échanges par service du créateur de l'échange
|
Filter activity by user scope: Filtrer les échanges par service du créateur de l'échange
|
||||||
'Filtered activity by user scope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%"
|
'Filtered activity by user scope: only %scopes%': "Filtré par service du créateur: uniquement %scopes%"
|
||||||
|
by_persons:
|
||||||
|
Filter activity by persons: Filtrer les échanges par usager participant
|
||||||
|
'Filtered activity by persons: only %persons%': 'Échanges filtrés par usagers participants: seulement %persons%'
|
||||||
|
persons taking part on the activity: Usagers participants à l'échange
|
||||||
|
|
||||||
aggregator:
|
aggregator:
|
||||||
activity:
|
activity:
|
||||||
@ -400,6 +404,9 @@ export:
|
|||||||
by_creator_job:
|
by_creator_job:
|
||||||
Group activity by creator job: Grouper les échanges par service du créateur de l'échange
|
Group activity by creator job: Grouper les échanges par service du créateur de l'échange
|
||||||
Calc date: Date de calcul du service du créateur de l'échange
|
Calc date: Date de calcul du service du créateur de l'échange
|
||||||
|
by_persons:
|
||||||
|
Group activity by persons: Grouper les échanges par usager participant
|
||||||
|
Persons: Usagers participants
|
||||||
|
|
||||||
generic_doc:
|
generic_doc:
|
||||||
filter:
|
filter:
|
||||||
|
@ -18,6 +18,21 @@ class LabelPersonHelper
|
|||||||
{
|
{
|
||||||
public function __construct(private readonly PersonRepository $personRepository, private readonly PersonRenderInterface $personRender) {}
|
public function __construct(private readonly PersonRepository $personRepository, private readonly PersonRenderInterface $personRender) {}
|
||||||
|
|
||||||
|
public function getLabel(string $key, array $values, string $header): callable
|
||||||
|
{
|
||||||
|
return function (null|int|string $value) use ($header): string {
|
||||||
|
if ('_header' === $value) {
|
||||||
|
return $header;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('' === $value || null === $value || null === $person = $this->personRepository->find($value)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->personRender->renderString($person, []);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public function getLabelMulti(string $key, array $values, string $header): callable
|
public function getLabelMulti(string $key, array $values, string $header): callable
|
||||||
{
|
{
|
||||||
return function ($value) use ($header) {
|
return function ($value) use ($header) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user