diff --git a/src/Bundle/ChillMainBundle/Entity/GeographicalUnit.php b/src/Bundle/ChillMainBundle/Entity/GeographicalUnit.php index b4c4388b6..e601ab147 100644 --- a/src/Bundle/ChillMainBundle/Entity/GeographicalUnit.php +++ b/src/Bundle/ChillMainBundle/Entity/GeographicalUnit.php @@ -44,7 +44,7 @@ class GeographicalUnit private string $unitRefId; /** - * @ORM\ManyToOne(targetEntity=GeographicalUnitLayer::class) + * @ORM\ManyToOne(targetEntity=GeographicalUnitLayer::class, inversedBy="units") */ private ?GeographicalUnitLayer $layer; diff --git a/src/Bundle/ChillMainBundle/Entity/GeographicalUnitLayer.php b/src/Bundle/ChillMainBundle/Entity/GeographicalUnitLayer.php index 54bde03ec..162d6ccf4 100644 --- a/src/Bundle/ChillMainBundle/Entity/GeographicalUnitLayer.php +++ b/src/Bundle/ChillMainBundle/Entity/GeographicalUnitLayer.php @@ -2,6 +2,8 @@ namespace Chill\MainBundle\Entity; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; /** @@ -29,6 +31,16 @@ class GeographicalUnitLayer */ private string $refId = ''; + /** + * @ORM\OneToMany(targetEntity=GeographicalUnit::class, mappedBy="layer") + */ + private Collection $units; + + public function __construct() + { + $this->units = new ArrayCollection(); + } + /** * @return int|null */ @@ -54,4 +66,20 @@ class GeographicalUnitLayer $this->name = $name; return $this; } + + /** + * @return string + */ + public function getRefId(): string + { + return $this->refId; + } + + /** + * @return Collection + */ + public function getUnits(): Collection + { + return $this->units; + } } \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/Repository/GeographicalUnitLayerLayerRepository.php b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitLayerLayerRepository.php new file mode 100644 index 000000000..7ef99ebac --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitLayerLayerRepository.php @@ -0,0 +1,59 @@ +repository = $em->getRepository($this->getClassName()); + } + + public function find($id): ?GeographicalUnitLayer + { + return $this->repository->find($id); + } + + /** + * @return array|GeographicalUnitLayer[] + */ + public function findAll(): array + { + return $this->repository->findAll(); + } + + /** + * @return array|GeographicalUnitLayer[] + */ + 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): ?GeographicalUnitLayer + { + return $this->repository->findOneBy($criteria); + } + + public function getClassName(): string + { + return GeographicalUnitLayer::class; + } + + public function findAllHavingUnits(): array + { + $qb = $this->repository->createQueryBuilder('l'); + + return $qb->where($qb->expr()->gt('SIZE(l.units)', 0)) + ->getQuery() + ->getResult(); + } +} \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/Repository/GeographicalUnitLayerRepositoryInterface.php b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitLayerRepositoryInterface.php new file mode 100644 index 000000000..e7c5abdd9 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitLayerRepositoryInterface.php @@ -0,0 +1,14 @@ +repository = $em->getRepository(...::class); + $this->geographicalUnitLayerRepository = $geographicalUnitLayerRepository; + $this->translatableStringHelper = $translatableStringHelper; } - */ /** * @inheritDoc */ public function getLabels($key, array $values, $data) { - return function ($value): string { - if ('_header' === $value) { - return 'Geographical unit'; - } + switch ($key) { + case 'acp_geog_agg_unitname': + return function ($value): string { + if ('_header' === $value) { + return 'acp_geog_agg_unitname'; + } - $g = $this->repository->find($value); + if (null === $value) { + return ''; + } - return $g; //... - }; + return $value; + }; + case 'acp_geog_agg_unitrefid': + return function ($value): string { + if ('_header' === $value) { + return 'acp_geog_agg_unitrefid'; + } + + if (null === $value) { + return ''; + } + + return $value; + }; + default: + throw new \UnexpectedValueException('this value should not happens'); + } } /** @@ -42,7 +72,7 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface */ public function getQueryKeys($data): array { - return ['geographicalunitstat_aggregator']; + return ['acp_geog_agg_unitname', 'acp_geog_agg_unitrefid']; } /** @@ -50,7 +80,22 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface */ public function buildForm(FormBuilderInterface $builder) { - // TODO: Implement buildForm() method. + $builder + ->add('date_calc', ChillDateType::class, [ + 'label' => 'Compute geographical location at date', + 'required' => true, + 'data' => new \DateTimeImmutable('today'), + 'input' => 'datetime_immutable', + ]) + ->add('level', EntityType::class, [ + 'label' => 'Geographical layer', + 'placeholder' => 'Select a geographical layer', + 'class' => GeographicalUnitLayer::class, + 'choices' => $this->geographicalUnitLayerRepository->findAllHavingUnits(), + 'choice_label' => function(GeographicalUnitLayer $item) { + return $this->translatableStringHelper->localize($item->getName()); + }, + ]); } /** @@ -74,16 +119,70 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface */ public function alterQuery(QueryBuilder $qb, $data) { + if (!in_array('acp_geog_agg_location_history', $qb->getAllAliases(), true)) { + $qb->leftJoin('acp.locationHistories', 'acp_geog_agg_location_history'); - //$qb->addSelect('... AS geographicalunitstat_aggregator'); + $qb->andWhere( + $qb->expr()->andX( + 'acp_geog_agg_location_history.startDate <= :acp_geog_aggregator_date', + $qb->expr()->orX( + 'acp_geog_agg_location_history.endDate IS NULL', + 'acp_geog_agg_location_history.endDate > :acp_geog_aggregator_date' + ) + ) + ); - $groupby = $qb->getDQLPart('groupBy'); - - if (!empty($groupBy)) { - $qb->addGroupBy('geographicalunitstat_aggregator'); - } else { - $qb->groupBy('geographicalunitstat_aggregator'); + $qb->setParameter('acp_geog_aggregator_date', $data['date_calc']); } + + // link between location history and person + if (!in_array('acp_geog_agg_address_person_location', $qb->getAllAliases(), true)) { + $qb->leftJoin( + PersonHouseholdAddress::class, + 'acp_geog_agg_address_person_location', + Join::WITH, + $qb->expr()->andX( + 'IDENTITY(acp_geog_agg_address_person_location.person) = IDENTITY(acp_geog_agg_location_history.personLocation)', + 'acp_geog_agg_address_person_location.validFrom < :acp_geog_aggregator_date', + $qb->expr()->orX( + 'acp_geog_agg_address_person_location.validTo > :acp_geog_aggregator_date', + $qb->expr()->isNull('acp_geog_agg_address_person_location.validTo') + ) + ) + ); + + $qb->setParameter('acp_geog_aggregator_date', $data['date_calc']); + } + + // we finally find an address + if (!in_array('acp_geog_agg_address', $qb->getAllAliases(), true)) { + $qb->leftJoin( + Address::class, + 'acp_geog_agg_address', + Join::WITH, + 'COALESCE(IDENTITY(acp_geog_agg_address_person_location.address), IDENTITY(acp_geog_agg_location_history.addressLocation)) = acp_geog_agg_address.id' + ); + } + + // and we do a join with units + $qb->leftJoin( + GeographicalUnit::class, + 'acp_geog_units', + Join::WITH, + 'ST_CONTAINS(acp_geog_units.geom, acp_geog_agg_address.point) = TRUE' + ); + + $qb->andWhere($qb->expr()->eq('acp_geog_units.layer', ':acp_geog_unit_layer')); + + $qb->setParameter('acp_geog_unit_layer', $data['level']); + + // we add group by + $qb + ->addSelect('acp_geog_units.unitName AS acp_geog_agg_unitname') + ->addSelect('acp_geog_units.unitRefId AS acp_geog_agg_unitrefid') + ->addGroupBy('acp_geog_agg_unitname') + ->addGroupBy('acp_geog_agg_unitrefid') + ; } /** @@ -93,4 +192,4 @@ final class GeographicalUnitStatAggregator implements AggregatorInterface { return Declarations::ACP_TYPE; } -} \ No newline at end of file +} diff --git a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml index c94b4963d..9e3ddf6a5 100644 --- a/src/Bundle/ChillPersonBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillPersonBundle/translations/messages.fr.yml @@ -456,7 +456,12 @@ Group by step: Grouper les parcours par statut du parcours Filter by geographical unit: Filtrer les parcours par zone géographique Group by geographical unit: Grouper les parcours par zone géographique +Compute geographical location at date: Date de calcul de la localisation géographique Geographical unit: Zone géographique +acp_geog_agg_unitname: Zone géographique +acp_geog_agg_unitrefid: Clé de la zone géographique +Geographical layer: Couche géographique +Select a geographical layer: Choisir une couche géographique Filter by socialaction: Filtrer les parcours par action d'accompagnement Accepted socialactions: Actions d'accompagnement