mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge remote-tracking branch 'origin/master' into upgrade-sf5
This commit is contained in:
commit
54d045f261
6
.changes/v2.22.0.md
Normal file
6
.changes/v2.22.0.md
Normal file
@ -0,0 +1,6 @@
|
||||
## v2.22.0 - 2024-06-25
|
||||
### Feature
|
||||
* ([#216](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/216)) [event bundle] exports added for the event module
|
||||
|
||||
### Traduction francophone
|
||||
* Exports sont ajoutés pour la module événement.
|
5
.changes/v2.22.1.md
Normal file
5
.changes/v2.22.1.md
Normal file
@ -0,0 +1,5 @@
|
||||
## v2.22.1 - 2024-07-01
|
||||
### Fixed
|
||||
* Remove debug word
|
||||
### DX
|
||||
* Add a command for reading official address DB from Luxembourg and update chill addresses
|
3
.changes/v2.22.2.md
Normal file
3
.changes/v2.22.2.md
Normal file
@ -0,0 +1,3 @@
|
||||
## v2.22.2 - 2024-07-03
|
||||
### Fixed
|
||||
* Remove scope required for event participation stats
|
17
CHANGELOG.md
17
CHANGELOG.md
@ -6,6 +6,23 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
|
||||
and is generated by [Changie](https://github.com/miniscruff/changie).
|
||||
|
||||
|
||||
## v2.22.2 - 2024-07-03
|
||||
### Fixed
|
||||
* Remove scope required for event participation stats
|
||||
|
||||
## v2.22.1 - 2024-07-01
|
||||
### Fixed
|
||||
* Remove debug word
|
||||
### DX
|
||||
* Add a command for reading official address DB from Luxembourg and update chill addresses
|
||||
|
||||
## v2.22.0 - 2024-06-25
|
||||
### Feature
|
||||
* ([#216](https://gitlab.com/Chill-Projet/chill-bundles/-/issues/216)) [event bundle] exports added for the event module
|
||||
|
||||
### Traduction francophone
|
||||
* Exports sont ajoutés pour la module événement.
|
||||
|
||||
## v2.21.0 - 2024-06-18
|
||||
### Feature
|
||||
* Add flash menu buttons in search results, to open directly a new calendar, or a new activity in an accompanying period
|
||||
|
@ -87,7 +87,6 @@
|
||||
<li>
|
||||
{% if bloc.type == 'user' %}
|
||||
<span class="badge-user">
|
||||
hello
|
||||
{{ item|chill_entity_render_box({'render': 'raw', 'addAltNames': false, 'at_date': entity.date }) }}
|
||||
</span>
|
||||
{% else %}
|
||||
|
@ -15,7 +15,7 @@ use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Entity\Participation;
|
||||
use Chill\EventBundle\Form\EventType;
|
||||
use Chill\EventBundle\Form\Type\PickEventType;
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||
@ -418,7 +418,6 @@ final class EventController extends AbstractController
|
||||
$builder->add('event_id', HiddenType::class, [
|
||||
'data' => $event->getId(),
|
||||
]);
|
||||
dump($event->getId());
|
||||
|
||||
return $builder->getForm();
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Entity\Participation;
|
||||
use Chill\EventBundle\Form\ParticipationType;
|
||||
use Chill\EventBundle\Repository\EventRepository;
|
||||
use Chill\EventBundle\Security\Authorization\ParticipationVoter;
|
||||
use Chill\EventBundle\Security\ParticipationVoter;
|
||||
use Chill\PersonBundle\Repository\PersonRepository;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
@ -11,8 +11,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\EventBundle\DependencyInjection;
|
||||
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
use Chill\EventBundle\Security\Authorization\ParticipationVoter;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\EventBundle\Security\ParticipationVoter;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
@ -33,12 +33,13 @@ class ChillEventExtension extends Extension implements PrependExtensionInterface
|
||||
|
||||
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../config'));
|
||||
$loader->load('services.yaml');
|
||||
$loader->load('services/authorization.yaml');
|
||||
$loader->load('services/security.yaml');
|
||||
$loader->load('services/fixtures.yaml');
|
||||
$loader->load('services/forms.yaml');
|
||||
$loader->load('services/repositories.yaml');
|
||||
$loader->load('services/search.yaml');
|
||||
$loader->load('services/timeline.yaml');
|
||||
$loader->load('services/export.yaml');
|
||||
}
|
||||
|
||||
/** (non-PHPdoc).
|
||||
|
@ -0,0 +1,110 @@
|
||||
<?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\EventBundle\Export\Aggregator;
|
||||
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class EventDateAggregator implements AggregatorInterface
|
||||
{
|
||||
private const CHOICES = [
|
||||
'by month' => 'month',
|
||||
'by week' => 'week',
|
||||
'by year' => 'year',
|
||||
];
|
||||
|
||||
private const DEFAULT_CHOICE = 'year';
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$order = null;
|
||||
|
||||
switch ($data['frequency']) {
|
||||
case 'month':
|
||||
$fmt = 'YYYY-MM';
|
||||
|
||||
break;
|
||||
|
||||
case 'week':
|
||||
$fmt = 'YYYY-IW';
|
||||
|
||||
break;
|
||||
|
||||
case 'year':
|
||||
$fmt = 'YYYY';
|
||||
$order = 'DESC';
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \RuntimeException(sprintf("The frequency data '%s' is invalid.", $data['frequency']));
|
||||
}
|
||||
|
||||
$qb->addSelect(sprintf("TO_CHAR(event.date, '%s') AS date_aggregator", $fmt));
|
||||
$qb->addGroupBy('date_aggregator');
|
||||
$qb->addOrderBy('date_aggregator', $order);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::EVENT;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('frequency', ChoiceType::class, [
|
||||
'choices' => self::CHOICES,
|
||||
'multiple' => false,
|
||||
'expanded' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return ['frequency' => self::DEFAULT_CHOICE];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
return static function ($value) use ($data): string {
|
||||
if ('_header' === $value) {
|
||||
return 'by '.$data['frequency'];
|
||||
}
|
||||
|
||||
if (null === $value) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return match ($data['frequency']) {
|
||||
default => $value,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return ['date_aggregator'];
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'Group event by date';
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
<?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\EventBundle\Export\Aggregator;
|
||||
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\EventBundle\Repository\EventTypeRepository;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class EventTypeAggregator implements AggregatorInterface
|
||||
{
|
||||
final public const KEY = 'event_type_aggregator';
|
||||
|
||||
public function __construct(protected EventTypeRepository $eventTypeRepository, protected TranslatableStringHelperInterface $translatableStringHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!\in_array('eventtype', $qb->getAllAliases(), true)) {
|
||||
$qb->leftJoin('event.type', 'eventtype');
|
||||
}
|
||||
|
||||
$qb->addSelect(sprintf('IDENTITY(event.type) AS %s', self::KEY));
|
||||
$qb->addGroupBy(self::KEY);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::EVENT;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form required for this aggregator
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): \Closure
|
||||
{
|
||||
return function (int|string|null $value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Event type';
|
||||
}
|
||||
|
||||
if (null === $value || '' === $value || null === $t = $this->eventTypeRepository->find($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->translatableStringHelper->localize($t->getName());
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return [self::KEY];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Group by event type';
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
<?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\EventBundle\Export\Aggregator;
|
||||
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\EventBundle\Repository\RoleRepository;
|
||||
use Chill\MainBundle\Export\AggregatorInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
class RoleAggregator implements AggregatorInterface
|
||||
{
|
||||
final public const KEY = 'part_role_aggregator';
|
||||
|
||||
public function __construct(protected RoleRepository $roleRepository, protected TranslatableStringHelperInterface $translatableStringHelper)
|
||||
{
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
if (!\in_array('event_part', $qb->getAllAliases(), true)) {
|
||||
$qb->leftJoin('event_part.role', 'role');
|
||||
}
|
||||
|
||||
$qb->addSelect(sprintf('IDENTITY(event_part.role) AS %s', self::KEY));
|
||||
$qb->addGroupBy(self::KEY);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::EVENT_PARTICIPANTS;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
// no form required for this aggregator
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data): \Closure
|
||||
{
|
||||
return function (int|string|null $value): string {
|
||||
if ('_header' === $value) {
|
||||
return 'Participant role';
|
||||
}
|
||||
|
||||
if (null === $value || '' === $value || null === $r = $this->roleRepository->find($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->translatableStringHelper->localize($r->getName());
|
||||
};
|
||||
}
|
||||
|
||||
public function getQueryKeys($data): array
|
||||
{
|
||||
return [self::KEY];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Group by participant role';
|
||||
}
|
||||
}
|
22
src/Bundle/ChillEventBundle/Export/Declarations.php
Normal file
22
src/Bundle/ChillEventBundle/Export/Declarations.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?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\EventBundle\Export;
|
||||
|
||||
/**
|
||||
* This class declare constants used for the export framework.
|
||||
*/
|
||||
abstract class Declarations
|
||||
{
|
||||
final public const EVENT = 'event';
|
||||
|
||||
final public const EVENT_PARTICIPANTS = 'event_participants';
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
<?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\EventBundle\Export\Export;
|
||||
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\EventBundle\Repository\ParticipationRepository;
|
||||
use Chill\EventBundle\Security\ParticipationVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Doctrine\ORM\Query;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
|
||||
readonly class CountEventParticipations implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
private bool $filterStatsByCenters;
|
||||
|
||||
public function __construct(
|
||||
private ParticipationRepository $participationRepository,
|
||||
ParameterBagInterface $parameterBag,
|
||||
) {
|
||||
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes()
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Count participants to an event by various parameters.';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of events';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_count_event_participants' !== $key) {
|
||||
throw new \LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
return static fn ($value) => '_header' === $value ? 'Count event participants' : $value;
|
||||
}
|
||||
|
||||
public function getQueryKeys($data)
|
||||
{
|
||||
return ['export_count_event_participants'];
|
||||
}
|
||||
|
||||
public function getResult($query, $data)
|
||||
{
|
||||
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Count event participants';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::EVENT_PARTICIPANTS;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->participationRepository
|
||||
->createQueryBuilder('event_part')
|
||||
->join('event_part.person', 'person');
|
||||
|
||||
$qb->select('COUNT(event_part.id) as export_count_event_participants');
|
||||
|
||||
if ($this->filterStatsByCenters) {
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person
|
||||
AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers);
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return ParticipationVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers()
|
||||
{
|
||||
return [
|
||||
Declarations::EVENT_PARTICIPANTS,
|
||||
PersonDeclarations::PERSON_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
128
src/Bundle/ChillEventBundle/Export/Export/CountEvents.php
Normal file
128
src/Bundle/ChillEventBundle/Export/Export/CountEvents.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?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\EventBundle\Export\Export;
|
||||
|
||||
use Chill\EventBundle\Repository\EventRepository;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\MainBundle\Export\ExportInterface;
|
||||
use Chill\MainBundle\Export\FormatterInterface;
|
||||
use Chill\MainBundle\Export\GroupedExportInterface;
|
||||
use Chill\PersonBundle\Entity\Person\PersonCenterHistory;
|
||||
use Doctrine\ORM\Query;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\PersonBundle\Export\Declarations as PersonDeclarations;
|
||||
|
||||
readonly class CountEvents implements ExportInterface, GroupedExportInterface
|
||||
{
|
||||
private bool $filterStatsByCenters;
|
||||
|
||||
public function __construct(
|
||||
private EventRepository $eventRepository,
|
||||
ParameterBagInterface $parameterBag,
|
||||
) {
|
||||
$this->filterStatsByCenters = $parameterBag->get('chill_main')['acl']['filter_stats_by_center'];
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getAllowedFormattersTypes()
|
||||
{
|
||||
return [FormatterInterface::TYPE_TABULAR];
|
||||
}
|
||||
|
||||
public function getDescription()
|
||||
{
|
||||
return 'Count events by various parameters.';
|
||||
}
|
||||
|
||||
public function getGroup(): string
|
||||
{
|
||||
return 'Exports of events';
|
||||
}
|
||||
|
||||
public function getLabels($key, array $values, $data)
|
||||
{
|
||||
if ('export_count_event' !== $key) {
|
||||
throw new \LogicException("the key {$key} is not used by this export");
|
||||
}
|
||||
|
||||
return static fn ($value) => '_header' === $value ? 'Number of events' : $value;
|
||||
}
|
||||
|
||||
public function getQueryKeys($data)
|
||||
{
|
||||
return ['export_count_event'];
|
||||
}
|
||||
|
||||
public function getResult($query, $data)
|
||||
{
|
||||
return $query->getQuery()->getResult(Query::HYDRATE_SCALAR);
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Count events';
|
||||
}
|
||||
|
||||
public function getType(): string
|
||||
{
|
||||
return Declarations::EVENT;
|
||||
}
|
||||
|
||||
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
|
||||
{
|
||||
$centers = array_map(static fn ($el) => $el['center'], $acl);
|
||||
|
||||
$qb = $this->eventRepository
|
||||
->createQueryBuilder('event')
|
||||
->leftJoin('event.participations', 'epart')
|
||||
->leftJoin('epart.person', 'person');
|
||||
|
||||
$qb->select('COUNT(event.id) as export_count_event');
|
||||
|
||||
if ($this->filterStatsByCenters) {
|
||||
$qb
|
||||
->andWhere(
|
||||
$qb->expr()->exists(
|
||||
'SELECT 1 FROM '.PersonCenterHistory::class.' acl_count_person_history WHERE acl_count_person_history.person = person
|
||||
AND acl_count_person_history.center IN (:authorized_centers)
|
||||
'
|
||||
)
|
||||
)
|
||||
->setParameter('authorized_centers', $centers);
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
public function requiredRole(): string
|
||||
{
|
||||
return EventVoter::STATS;
|
||||
}
|
||||
|
||||
public function supportsModifiers()
|
||||
{
|
||||
return [
|
||||
Declarations::EVENT,
|
||||
PersonDeclarations::PERSON_TYPE,
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
<?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\EventBundle\Export\Filter;
|
||||
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Form\Type\PickRollingDateType;
|
||||
use Chill\MainBundle\Service\RollingDate\RollingDate;
|
||||
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
||||
use Doctrine\ORM\Query\Expr;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class EventDateFilter implements FilterInterface
|
||||
{
|
||||
public function __construct(protected TranslatorInterface $translator, private readonly RollingDateConverterInterface $rollingDateConverter)
|
||||
{
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$where = $qb->getDQLPart('where');
|
||||
$clause = $qb->expr()->between(
|
||||
'event.date',
|
||||
':date_from',
|
||||
':date_to'
|
||||
);
|
||||
|
||||
if ($where instanceof Expr\Andx) {
|
||||
$where->add($clause);
|
||||
} else {
|
||||
$where = $qb->expr()->andX($clause);
|
||||
}
|
||||
|
||||
$qb->add('where', $where);
|
||||
$qb->setParameter(
|
||||
'date_from',
|
||||
$this->rollingDateConverter->convert($data['date_from'])
|
||||
);
|
||||
$qb->setParameter(
|
||||
'date_to',
|
||||
$this->rollingDateConverter->convert($data['date_to'])
|
||||
);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::EVENT;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder
|
||||
->add('date_from', PickRollingDateType::class, [
|
||||
'label' => 'Events after this date',
|
||||
])
|
||||
->add('date_to', PickRollingDateType::class, [
|
||||
'label' => 'Events before this date',
|
||||
]);
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return ['date_from' => new RollingDate(RollingDate::T_YEAR_PREVIOUS_START), 'date_to' => new RollingDate(RollingDate::T_TODAY)];
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string')
|
||||
{
|
||||
return [
|
||||
'Filtered by date of event: only between %date_from% and %date_to%',
|
||||
[
|
||||
'%date_from%' => $this->rollingDateConverter->convert($data['date_from'])->format('d-m-Y'),
|
||||
'%date_to%' => $this->rollingDateConverter->convert($data['date_to'])->format('d-m-Y'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Filtered by event date';
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
<?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\EventBundle\Export\Filter;
|
||||
|
||||
use Chill\EventBundle\Entity\EventType;
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\EventBundle\Repository\EventTypeRepository;
|
||||
use Chill\MainBundle\Export\ExportElementValidatedInterface;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
class EventTypeFilter implements ExportElementValidatedInterface, FilterInterface
|
||||
{
|
||||
public function __construct(
|
||||
protected TranslatableStringHelperInterface $translatableStringHelper,
|
||||
protected EventTypeRepository $eventTypeRepository
|
||||
) {
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$clause = $qb->expr()->in('event.type', ':selected_event_types');
|
||||
|
||||
$qb->andWhere($clause);
|
||||
$qb->setParameter('selected_event_types', $data['types']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::EVENT;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('types', EntityType::class, [
|
||||
'choices' => $this->eventTypeRepository->findAllActive(),
|
||||
'class' => EventType::class,
|
||||
'choice_label' => fn (EventType $ety) => $this->translatableStringHelper->localize($ety->getName()),
|
||||
'multiple' => true,
|
||||
'expanded' => false,
|
||||
'attr' => [
|
||||
'class' => 'select2',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string')
|
||||
{
|
||||
$typeNames = array_map(
|
||||
fn (EventType $t): string => $this->translatableStringHelper->localize($t->getName()),
|
||||
$this->eventTypeRepository->findBy(['id' => $data['types'] instanceof \Doctrine\Common\Collections\Collection ? $data['types']->toArray() : $data['types']])
|
||||
);
|
||||
|
||||
return ['Filtered by event type: only %list%', [
|
||||
'%list%' => implode(', ', $typeNames),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Filtered by event type';
|
||||
}
|
||||
|
||||
public function validateForm($data, ExecutionContextInterface $context)
|
||||
{
|
||||
if (null === $data['types'] || 0 === \count($data['types'])) {
|
||||
$context
|
||||
->buildViolation('At least one type must be chosen')
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
}
|
95
src/Bundle/ChillEventBundle/Export/Filter/RoleFilter.php
Normal file
95
src/Bundle/ChillEventBundle/Export/Filter/RoleFilter.php
Normal file
@ -0,0 +1,95 @@
|
||||
<?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\EventBundle\Export\Filter;
|
||||
|
||||
use Chill\EventBundle\Entity\Role;
|
||||
use Chill\EventBundle\Export\Declarations;
|
||||
use Chill\EventBundle\Repository\RoleRepository;
|
||||
use Chill\MainBundle\Export\ExportElementValidatedInterface;
|
||||
use Chill\MainBundle\Export\FilterInterface;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
class RoleFilter implements ExportElementValidatedInterface, FilterInterface
|
||||
{
|
||||
public function __construct(
|
||||
protected TranslatableStringHelperInterface $translatableStringHelper,
|
||||
protected RoleRepository $roleRepository
|
||||
) {
|
||||
}
|
||||
|
||||
public function addRole(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function alterQuery(QueryBuilder $qb, $data)
|
||||
{
|
||||
$clause = $qb->expr()->in('event_part.role', ':selected_part_roles');
|
||||
|
||||
$qb->andWhere($clause);
|
||||
$qb->setParameter('selected_part_roles', $data['part_roles']);
|
||||
}
|
||||
|
||||
public function applyOn(): string
|
||||
{
|
||||
return Declarations::EVENT_PARTICIPANTS;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder)
|
||||
{
|
||||
$builder->add('part_roles', EntityType::class, [
|
||||
'choices' => $this->roleRepository->findAllActive(),
|
||||
'class' => Role::class,
|
||||
'choice_label' => fn (Role $r) => $this->translatableStringHelper->localize($r->getName()),
|
||||
'multiple' => true,
|
||||
'expanded' => false,
|
||||
'attr' => [
|
||||
'class' => 'select2',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function getFormDefaultData(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function describeAction($data, $format = 'string')
|
||||
{
|
||||
$roleNames = array_map(
|
||||
fn (Role $r): string => $this->translatableStringHelper->localize($r->getName()),
|
||||
$this->roleRepository->findBy(['id' => $data['part_roles'] instanceof \Doctrine\Common\Collections\Collection ? $data['part_roles']->toArray() : $data['part_roles']])
|
||||
);
|
||||
|
||||
return ['Filtered by participant roles: only %list%', [
|
||||
'%list%' => implode(', ', $roleNames),
|
||||
]];
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
{
|
||||
return 'Filter by participant roles';
|
||||
}
|
||||
|
||||
public function validateForm($data, ExecutionContextInterface $context)
|
||||
{
|
||||
if (null === $data['part_roles'] || 0 === \count($data['part_roles'])) {
|
||||
$context
|
||||
->buildViolation('At least one role must be chosen')
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\EventBundle\Menu;
|
||||
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||
use Knp\Menu\MenuItem;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
|
@ -11,7 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\EventBundle\Menu;
|
||||
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||
use Knp\Menu\MenuItem;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
|
@ -13,7 +13,7 @@ namespace Chill\EventBundle\Repository;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Entity\Participation;
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelperForCurrentUserInterface;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
|
@ -12,13 +12,57 @@ declare(strict_types=1);
|
||||
namespace Chill\EventBundle\Repository;
|
||||
|
||||
use Chill\EventBundle\Entity\Role;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ObjectRepository;
|
||||
|
||||
class RoleRepository extends ServiceEntityRepository
|
||||
readonly class RoleRepository implements ObjectRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
private EntityRepository $repository;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager, private TranslatableStringHelper $translatableStringHelper)
|
||||
{
|
||||
parent::__construct($registry, Role::class);
|
||||
$this->repository = $entityManager->getRepository(Role::class);
|
||||
}
|
||||
|
||||
public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder
|
||||
{
|
||||
return $this->repository->createQueryBuilder($alias, $indexBy);
|
||||
}
|
||||
|
||||
public function find($id)
|
||||
{
|
||||
return $this->repository->find($id);
|
||||
}
|
||||
|
||||
public function findAll(): array
|
||||
{
|
||||
return $this->repository->findAll();
|
||||
}
|
||||
|
||||
public function findAllActive(): array
|
||||
{
|
||||
$roles = $this->repository->findBy(['active' => true]);
|
||||
|
||||
usort($roles, fn (Role $a, Role $b) => $this->translatableStringHelper->localize($a->getName()) <=> $this->translatableStringHelper->localize($b->getName()));
|
||||
|
||||
return $roles;
|
||||
}
|
||||
|
||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
||||
{
|
||||
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
||||
}
|
||||
|
||||
public function findOneBy(array $criteria)
|
||||
{
|
||||
return $this->repository->findOneBy($criteria);
|
||||
}
|
||||
|
||||
public function getClassName(): string
|
||||
{
|
||||
return Role::class;
|
||||
}
|
||||
}
|
||||
|
@ -9,18 +9,19 @@ declare(strict_types=1);
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Security\Authorization;
|
||||
namespace Chill\EventBundle\Security;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface;
|
||||
use Chill\MainBundle\Security\Authorization\VoterHelperInterface;
|
||||
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
|
||||
|
||||
/**
|
||||
* Description of EventVoter.
|
||||
@ -42,61 +43,46 @@ class EventVoter extends AbstractChillVoter implements ProvideRoleHierarchyInter
|
||||
|
||||
final public const UPDATE = 'CHILL_EVENT_UPDATE';
|
||||
|
||||
/**
|
||||
* @var AccessDecisionManagerInterface
|
||||
*/
|
||||
protected $accessDecisionManager;
|
||||
final public const STATS = 'CHILL_EVENT_STATS';
|
||||
|
||||
/**
|
||||
* @var AuthorizationHelper
|
||||
*/
|
||||
protected $authorizationHelper;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
private readonly VoterHelperInterface $voterHelper;
|
||||
|
||||
public function __construct(
|
||||
AccessDecisionManagerInterface $accessDecisionManager,
|
||||
AuthorizationHelper $authorizationHelper,
|
||||
LoggerInterface $logger
|
||||
private readonly AuthorizationHelper $authorizationHelper,
|
||||
private readonly LoggerInterface $logger,
|
||||
VoterHelperFactoryInterface $voterHelperFactory
|
||||
) {
|
||||
$this->accessDecisionManager = $accessDecisionManager;
|
||||
$this->authorizationHelper = $authorizationHelper;
|
||||
$this->logger = $logger;
|
||||
$this->voterHelper = $voterHelperFactory
|
||||
->generate(self::class)
|
||||
->addCheckFor(null, [self::SEE])
|
||||
->addCheckFor(Event::class, [...self::ROLES])
|
||||
->addCheckFor(Person::class, [self::SEE, self::CREATE])
|
||||
->addCheckFor(Center::class, [self::STATS])
|
||||
->build();
|
||||
}
|
||||
|
||||
public function getRoles(): array
|
||||
{
|
||||
return self::ROLES;
|
||||
return [...self::ROLES, self::STATS];
|
||||
}
|
||||
|
||||
public function getRolesWithHierarchy(): array
|
||||
{
|
||||
return [
|
||||
'Event' => self::ROLES,
|
||||
'Event' => $this->getRoles(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getRolesWithoutScope(): array
|
||||
{
|
||||
return [];
|
||||
return [self::ROLES, self::STATS];
|
||||
}
|
||||
|
||||
public function supports($attribute, $subject)
|
||||
{
|
||||
return ($subject instanceof Event && \in_array($attribute, self::ROLES, true))
|
||||
|| ($subject instanceof Person && \in_array($attribute, [self::CREATE, self::SEE], true))
|
||||
|| (null === $subject && self::SEE === $attribute);
|
||||
return $this->voterHelper->supports($attribute, $subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param Event $subject
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
|
||||
{
|
||||
$this->logger->debug(sprintf('Voting from %s class', self::class));
|
||||
@ -118,15 +104,5 @@ class EventVoter extends AbstractChillVoter implements ProvideRoleHierarchyInter
|
||||
->getReachableCenters($token->getUser(), $attribute);
|
||||
|
||||
return \count($centers) > 0;
|
||||
|
||||
if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->authorizationHelper->userHasAccess(
|
||||
$token->getUser(),
|
||||
$subject,
|
||||
$attribute
|
||||
);
|
||||
}
|
||||
}
|
@ -9,18 +9,19 @@ declare(strict_types=1);
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Chill\EventBundle\Security\Authorization;
|
||||
namespace Chill\EventBundle\Security;
|
||||
|
||||
use Chill\EventBundle\Entity\Participation;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
|
||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||
use Chill\MainBundle\Security\Authorization\VoterHelperFactoryInterface;
|
||||
use Chill\MainBundle\Security\Authorization\VoterHelperInterface;
|
||||
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
|
||||
use Chill\PersonBundle\Entity\Person;
|
||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
|
||||
|
||||
class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
|
||||
{
|
||||
@ -39,58 +40,48 @@ class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierar
|
||||
|
||||
final public const UPDATE = 'CHILL_EVENT_PARTICIPATION_UPDATE';
|
||||
|
||||
/**
|
||||
* @var AccessDecisionManagerInterface
|
||||
*/
|
||||
protected $accessDecisionManager;
|
||||
final public const STATS = 'CHILL_EVENT_PARTICIPATION_STATS';
|
||||
|
||||
/**
|
||||
* @var AuthorizationHelper
|
||||
*/
|
||||
protected $authorizationHelper;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
private readonly VoterHelperInterface $voterHelper;
|
||||
|
||||
public function __construct(
|
||||
AccessDecisionManagerInterface $accessDecisionManager,
|
||||
AuthorizationHelper $authorizationHelper,
|
||||
LoggerInterface $logger
|
||||
private readonly AuthorizationHelper $authorizationHelper,
|
||||
private readonly LoggerInterface $logger,
|
||||
VoterHelperFactoryInterface $voterHelperFactory
|
||||
) {
|
||||
$this->accessDecisionManager = $accessDecisionManager;
|
||||
$this->authorizationHelper = $authorizationHelper;
|
||||
$this->logger = $logger;
|
||||
$this->voterHelper = $voterHelperFactory
|
||||
->generate(self::class)
|
||||
->addCheckFor(null, [self::SEE])
|
||||
->addCheckFor(Participation::class, [...self::ROLES])
|
||||
->addCheckFor(Person::class, [self::SEE, self::CREATE])
|
||||
->addCheckFor(Center::class, [self::STATS])
|
||||
->build();
|
||||
}
|
||||
|
||||
public function getRoles(): array
|
||||
{
|
||||
return self::ROLES;
|
||||
return [...self::ROLES, self::STATS];
|
||||
}
|
||||
|
||||
public function getRolesWithHierarchy(): array
|
||||
{
|
||||
return [
|
||||
'Event' => self::ROLES,
|
||||
'Participation' => $this->getRoles(),
|
||||
];
|
||||
}
|
||||
|
||||
public function getRolesWithoutScope(): array
|
||||
{
|
||||
return [];
|
||||
return [self::ROLES, self::STATS];
|
||||
}
|
||||
|
||||
public function supports($attribute, $subject)
|
||||
{
|
||||
return ($subject instanceof Participation && \in_array($attribute, self::ROLES, true))
|
||||
|| ($subject instanceof Person && \in_array($attribute, [self::CREATE, self::SEE], true))
|
||||
|| (null === $subject && self::SEE === $attribute);
|
||||
return $this->voterHelper->supports($attribute, $subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $attribute
|
||||
* @param Participation $subject
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@ -115,15 +106,5 @@ class ParticipationVoter extends AbstractChillVoter implements ProvideRoleHierar
|
||||
->getReachableCenters($token->getUser(), $attribute);
|
||||
|
||||
return \count($centers) > 0;
|
||||
|
||||
if (!$this->accessDecisionManager->decide($token, [PersonVoter::SEE], $person)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->authorizationHelper->userHasAccess(
|
||||
$token->getUser(),
|
||||
$subject,
|
||||
$attribute
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
<?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\EventBundle\Tests\Export;
|
||||
|
||||
use Chill\EventBundle\Export\Export\CountEventParticipations;
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class CountEventParticipationsTest extends KernelTestCase
|
||||
{
|
||||
private CountEventParticipations $countEventParticipations;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
self::bootKernel();
|
||||
$this->countEventParticipations = self::$container->get(CountEventParticipations::class);
|
||||
}
|
||||
|
||||
public function testExecuteQuery(): void
|
||||
{
|
||||
$qb = $this->countEventParticipations->initiateQuery([], [], [])
|
||||
->setMaxResults(1);
|
||||
|
||||
$results = $qb->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY);
|
||||
|
||||
self::assertIsArray($results, 'smoke test: test that the result is an array');
|
||||
}
|
||||
}
|
43
src/Bundle/ChillEventBundle/Tests/Export/CountEventTest.php
Normal file
43
src/Bundle/ChillEventBundle/Tests/Export/CountEventTest.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?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\EventBundle\Tests\Export;
|
||||
|
||||
use Chill\EventBundle\Export\Export\CountEvents;
|
||||
use Doctrine\ORM\AbstractQuery;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class CountEventTest extends KernelTestCase
|
||||
{
|
||||
private CountEvents $countEvents;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
self::bootKernel();
|
||||
$this->countEvents = self::$container->get(CountEvents::class);
|
||||
}
|
||||
|
||||
public function testExecuteQuery(): void
|
||||
{
|
||||
$qb = $this->countEvents->initiateQuery([], [], [])
|
||||
->setMaxResults(1);
|
||||
|
||||
$results = $qb->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY);
|
||||
|
||||
self::assertIsArray($results, 'smoke test: test that the result is an array');
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
<?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 Export\aggregators;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Export\Aggregator\EventDateAggregator;
|
||||
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class EventDateAggregatorTest extends AbstractAggregatorTest
|
||||
{
|
||||
private $aggregator;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$this->aggregator = self::$container->get(EventDateAggregator::class);
|
||||
}
|
||||
|
||||
public function getAggregator()
|
||||
{
|
||||
return $this->aggregator;
|
||||
}
|
||||
|
||||
public function getFormData(): array|\Generator
|
||||
{
|
||||
yield ['frequency' => 'YYYY'];
|
||||
yield ['frequency' => 'YYYY-MM'];
|
||||
yield ['frequency' => 'YYYY-IV'];
|
||||
}
|
||||
|
||||
public function getQueryBuilders(): array
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('event.id')
|
||||
->from(Event::class, 'event'),
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
<?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 Export\aggregators;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Export\Aggregator\EventTypeAggregator;
|
||||
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class EventTypeAggregatorTest extends AbstractAggregatorTest
|
||||
{
|
||||
private $aggregator;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$this->aggregator = self::$container->get(EventTypeAggregator::class);
|
||||
}
|
||||
|
||||
public function getAggregator()
|
||||
{
|
||||
return $this->aggregator;
|
||||
}
|
||||
|
||||
public function getFormData(): array
|
||||
{
|
||||
return [
|
||||
[],
|
||||
];
|
||||
}
|
||||
|
||||
public function getQueryBuilders(): array
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('event.id')
|
||||
->from(Event::class, 'event'),
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
<?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 Export\aggregators;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Entity\Participation;
|
||||
use Chill\EventBundle\Export\Aggregator\RoleAggregator;
|
||||
use Chill\MainBundle\Test\Export\AbstractAggregatorTest;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class RoleAggregatorTest extends AbstractAggregatorTest
|
||||
{
|
||||
private $aggregator;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$this->aggregator = self::$container->get(RoleAggregator::class);
|
||||
}
|
||||
|
||||
public function getAggregator()
|
||||
{
|
||||
return $this->aggregator;
|
||||
}
|
||||
|
||||
public function getFormData(): array
|
||||
{
|
||||
return [
|
||||
[],
|
||||
];
|
||||
}
|
||||
|
||||
public function getQueryBuilders(): array
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('event.id')
|
||||
->from(Event::class, 'event'),
|
||||
$em->createQueryBuilder()
|
||||
->select('event_part')
|
||||
->from(Participation::class, 'event_part'),
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
<?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 Export\filters;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Export\Filter\EventDateFilter;
|
||||
use Chill\MainBundle\Service\RollingDate\RollingDate;
|
||||
use Chill\MainBundle\Service\RollingDate\RollingDateConverterInterface;
|
||||
use Chill\MainBundle\Test\Export\AbstractFilterTest;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class EventDateFilterTest extends AbstractFilterTest
|
||||
{
|
||||
private RollingDateConverterInterface $rollingDateConverter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
self::bootKernel();
|
||||
|
||||
$this->rollingDateConverter = self::$container->get(RollingDateConverterInterface::class);
|
||||
}
|
||||
|
||||
public function getFilter()
|
||||
{
|
||||
return new EventDateFilter($this->rollingDateConverter);
|
||||
}
|
||||
|
||||
public function getFormData()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'date_from' => new RollingDate(RollingDate::T_YEAR_CURRENT_START),
|
||||
'date_to' => new RollingDate(RollingDate::T_TODAY),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function getQueryBuilders(): array
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('event.id')
|
||||
->from(Event::class, 'event'),
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
<?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 Export\filters;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Entity\EventType;
|
||||
use Chill\EventBundle\Export\Filter\EventTypeFilter;
|
||||
use Chill\MainBundle\Test\Export\AbstractFilterTest;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class EventTypeFilterTest extends AbstractFilterTest
|
||||
{
|
||||
private EventTypeFilter $filter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
$this->filter = self::$container->get(EventTypeFilter::class);
|
||||
}
|
||||
|
||||
public function getFilter(): EventTypeFilter|\Chill\MainBundle\Export\FilterInterface
|
||||
{
|
||||
return $this->filter;
|
||||
}
|
||||
|
||||
public function getFormData()
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
$array = $em->createQueryBuilder()
|
||||
->from(EventType::class, 'et')
|
||||
->select('et')
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($array as $a) {
|
||||
$data[] = [
|
||||
'types' => new ArrayCollection([$a]),
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getQueryBuilders()
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('event.id')
|
||||
->from(Event::class, 'event'),
|
||||
];
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
<?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 Export\filters;
|
||||
|
||||
use Chill\EventBundle\Entity\Event;
|
||||
use Chill\EventBundle\Entity\Participation;
|
||||
use Chill\EventBundle\Entity\Role;
|
||||
use Chill\EventBundle\Export\Filter\RoleFilter;
|
||||
use Chill\MainBundle\Test\Export\AbstractFilterTest;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @coversNothing
|
||||
*/
|
||||
class RoleFilterTest extends AbstractFilterTest
|
||||
{
|
||||
private RoleFilter $filter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$this->filter = self::$container->get(RoleFilter::class);
|
||||
}
|
||||
|
||||
public function getFilter()
|
||||
{
|
||||
return $this->filter;
|
||||
}
|
||||
|
||||
public function getFormData(): array
|
||||
{
|
||||
self::bootKernel();
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
$array = $em->createQueryBuilder()
|
||||
->from(Role::class, 'r')
|
||||
->select('r')
|
||||
->getQuery()
|
||||
->setMaxResults(1)
|
||||
->getResult();
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($array as $a) {
|
||||
$data[] = [
|
||||
'roles' => new ArrayCollection([$a]),
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getQueryBuilders()
|
||||
{
|
||||
self::bootKernel();
|
||||
|
||||
$em = self::$container->get(EntityManagerInterface::class);
|
||||
|
||||
return [
|
||||
$em->createQueryBuilder()
|
||||
->select('event.id')
|
||||
->from(Event::class, 'event'),
|
||||
$em->createQueryBuilder()
|
||||
->select('event_part')
|
||||
->from(Participation::class, 'event_part'),
|
||||
];
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ declare(strict_types=1);
|
||||
namespace Chill\EventBundle\Tests\Repository;
|
||||
|
||||
use Chill\EventBundle\Repository\EventACLAwareRepository;
|
||||
use Chill\EventBundle\Security\Authorization\EventVoter;
|
||||
use Chill\EventBundle\Security\EventVoter;
|
||||
use Chill\MainBundle\Entity\Center;
|
||||
use Chill\MainBundle\Entity\Scope;
|
||||
use Chill\MainBundle\Entity\User;
|
||||
|
@ -1,18 +0,0 @@
|
||||
services:
|
||||
chill_event.event_voter:
|
||||
class: Chill\EventBundle\Security\Authorization\EventVoter
|
||||
arguments:
|
||||
- "@security.access.decision_manager"
|
||||
- "@chill.main.security.authorization.helper"
|
||||
- "@logger"
|
||||
tags:
|
||||
- { name: security.voter }
|
||||
|
||||
chill_event.event_participation:
|
||||
class: Chill\EventBundle\Security\Authorization\ParticipationVoter
|
||||
arguments:
|
||||
- "@security.access.decision_manager"
|
||||
- "@chill.main.security.authorization.helper"
|
||||
- "@logger"
|
||||
tags:
|
||||
- { name: security.voter }
|
41
src/Bundle/ChillEventBundle/config/services/export.yaml
Normal file
41
src/Bundle/ChillEventBundle/config/services/export.yaml
Normal file
@ -0,0 +1,41 @@
|
||||
services:
|
||||
_defaults:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
# indicators
|
||||
|
||||
Chill\EventBundle\Export\Export\CountEvents:
|
||||
tags:
|
||||
- { name: chill.export, alias: 'count_events' }
|
||||
Chill\EventBundle\Export\Export\CountEventParticipations:
|
||||
tags:
|
||||
- { name: chill.export, alias: 'count_event_participants' }
|
||||
|
||||
# filters
|
||||
|
||||
Chill\EventBundle\Export\Filter\EventDateFilter:
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'event_date_filter' }
|
||||
|
||||
Chill\EventBundle\Export\Filter\EventTypeFilter:
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'event_type_filter' }
|
||||
|
||||
Chill\EventBundle\Export\Filter\RoleFilter:
|
||||
tags:
|
||||
- { name: chill.export_filter, alias: 'role_filter' }
|
||||
|
||||
# aggregators
|
||||
|
||||
Chill\EventBundle\Export\Aggregator\EventTypeAggregator:
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: event_type_aggregator }
|
||||
|
||||
Chill\EventBundle\Export\Aggregator\EventDateAggregator:
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: event_date_aggregator }
|
||||
|
||||
Chill\EventBundle\Export\Aggregator\RoleAggregator:
|
||||
tags:
|
||||
- { name: chill.export_aggregator, alias: role_aggregator }
|
14
src/Bundle/ChillEventBundle/config/services/security.yaml
Normal file
14
src/Bundle/ChillEventBundle/config/services/security.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
services:
|
||||
Chill\EventBundle\Security\EventVoter:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: security.voter }
|
||||
- { name: chill.role }
|
||||
|
||||
Chill\EventBundle\Security\ParticipationVoter:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
tags:
|
||||
- { name: security.voter }
|
||||
- { name: chill.role }
|
@ -81,9 +81,31 @@ Pick an event: Choisir un événement
|
||||
Pick a type of event: Choisir un type d'événement
|
||||
Pick a moderator: Choisir un animateur
|
||||
|
||||
# exports
|
||||
Select a format: Choisir un format
|
||||
Export: Exporter
|
||||
|
||||
Count events: Nombre d'événements
|
||||
Count events by various parameters.: Compte le nombre d'événements selon divers critères
|
||||
Exports of events: Exports d'événements
|
||||
|
||||
Filtered by event date: Filtrer par date d'événement
|
||||
'Filtered by date of event: only between %date_from% and %date_to%': "Filtré par date d'événement: uniquement entre le %date_from% et le %date_to%"
|
||||
Events after this date: Événements après cette date
|
||||
Events before this date: Événements avant cette date
|
||||
Filtered by event type: Filtrer par type d'événement
|
||||
'Filtered by event type: only %list%': "Filtré par type: uniquement %list%"
|
||||
Group event by date: Grouper par date d'événement
|
||||
Group by event type: Grouper par type d'événement
|
||||
|
||||
Count event participants: Nombre de participations
|
||||
Count participants to an event by various parameters.: Compte le nombre de participations selon divers critères
|
||||
Exports of event participants: Exports de participations
|
||||
'Filtered by participant roles: only %list%': "Filtré par rôles de participation: uniquement %list%"
|
||||
Filter by participant roles: Filtrer par rôles de participation
|
||||
Part roles: Rôles de participation
|
||||
Group by participant role: Grouper par rôle de participation
|
||||
|
||||
|
||||
Events configuration: Configuration des événements
|
||||
Events configuration menu: Menu des événements
|
||||
|
@ -0,0 +1,40 @@
|
||||
<?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\Command;
|
||||
|
||||
use Chill\MainBundle\Service\Import\AddressReferenceLU;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class LoadAddressesLUFromBDAddressCommand extends Command
|
||||
{
|
||||
protected static $defaultDescription = 'Import LUX addresses from BD addresses (see https://data.public.lu/fr/datasets/adresses-georeferencees-bd-adresses/)';
|
||||
|
||||
public function __construct(
|
||||
private readonly AddressReferenceLU $addressImporter,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('chill:main:address-ref-lux');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->addressImporter->import();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
<?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\Import;
|
||||
|
||||
use League\Csv\Reader;
|
||||
use League\Csv\Statement;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
class AddressReferenceLU
|
||||
{
|
||||
private const RELEASE = 'https://data.public.lu/fr/datasets/r/5cadc5b8-6a7d-4283-87bc-f9e58dd771f7';
|
||||
|
||||
public function __construct(private readonly HttpClientInterface $client, private readonly AddressReferenceBaseImporter $addressBaseImporter, private readonly PostalCodeBaseImporter $postalCodeBaseImporter, private readonly AddressToReferenceMatcher $addressToReferenceMatcher)
|
||||
{
|
||||
}
|
||||
|
||||
public function import(): void
|
||||
{
|
||||
$downloadUrl = self::RELEASE;
|
||||
|
||||
$response = $this->client->request('GET', $downloadUrl);
|
||||
|
||||
if (200 !== $response->getStatusCode()) {
|
||||
throw new \Exception('Could not download CSV: '.$response->getStatusCode());
|
||||
}
|
||||
|
||||
$file = tmpfile();
|
||||
|
||||
foreach ($this->client->stream($response) as $chunk) {
|
||||
fwrite($file, $chunk->getContent());
|
||||
}
|
||||
|
||||
fseek($file, 0);
|
||||
|
||||
$csv = Reader::createFromStream($file);
|
||||
$csv->setDelimiter(';');
|
||||
$csv->setHeaderOffset(0);
|
||||
|
||||
$this->process_postal_code($csv);
|
||||
|
||||
$this->process_address($csv);
|
||||
|
||||
$this->addressToReferenceMatcher->checkAddressesMatchingReferences();
|
||||
|
||||
fclose($file);
|
||||
}
|
||||
|
||||
private function process_address(Reader $csv): void
|
||||
{
|
||||
$stmt = Statement::create()->process($csv);
|
||||
foreach ($stmt as $record) {
|
||||
$this->addressBaseImporter->importAddress(
|
||||
$record['id_geoportail'],
|
||||
$record['code_postal'],
|
||||
$record['code_postal'],
|
||||
$record['rue'],
|
||||
$record['numero'],
|
||||
'bd-addresses.lux',
|
||||
(float) $record['lat_wgs84'],
|
||||
(float) $record['lon_wgs84'],
|
||||
4326
|
||||
);
|
||||
}
|
||||
|
||||
$this->addressBaseImporter->finalize();
|
||||
}
|
||||
|
||||
private function process_postal_code(Reader $csv): void
|
||||
{
|
||||
$stmt = Statement::create()->process($csv);
|
||||
$arr_postal_codes = [];
|
||||
foreach ($stmt as $record) {
|
||||
if (false === \array_key_exists($record['code_postal'], $arr_postal_codes)) {
|
||||
$this->postalCodeBaseImporter->importCode(
|
||||
'LU',
|
||||
trim((string) $record['localite']),
|
||||
trim((string) $record['code_postal']),
|
||||
trim((string) $record['code_postal']),
|
||||
'bd-addresses.lux',
|
||||
(float) $record['lat_wgs84'],
|
||||
(float) $record['lon_wgs84'],
|
||||
4326
|
||||
);
|
||||
$arr_postal_codes[$record['code_postal']] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -59,6 +59,12 @@ services:
|
||||
tags:
|
||||
- { name: console.command }
|
||||
|
||||
Chill\MainBundle\Command\LoadAddressesLUFromBDAddressCommand:
|
||||
autoconfigure: true
|
||||
autowire: true
|
||||
tags:
|
||||
- { name: console.command }
|
||||
|
||||
Chill\MainBundle\Command\ExecuteCronJobCommand:
|
||||
autoconfigure: true
|
||||
autowire: true
|
||||
|
Loading…
x
Reference in New Issue
Block a user