diff --git a/src/Bundle/ChillMainBundle/Entity/GeographicalUnit.php b/src/Bundle/ChillMainBundle/Entity/GeographicalUnit.php index e601ab147..8c704a166 100644 --- a/src/Bundle/ChillMainBundle/Entity/GeographicalUnit.php +++ b/src/Bundle/ChillMainBundle/Entity/GeographicalUnit.php @@ -53,20 +53,36 @@ class GeographicalUnit return $this->id; } - public function getLayerName(): ?string - { - return $this->layerName; - } - public function getUnitName(): ?string { return $this->unitName; } - public function setLayerName(?string $layerName): self + /** + * @return GeographicalUnitLayer|null + */ + public function getLayer(): ?GeographicalUnitLayer { - $this->layerName = $layerName; + return $this->layer; + } + /** + * @param string $unitRefId + * @return GeographicalUnit + */ + public function setUnitRefId(string $unitRefId): GeographicalUnit + { + $this->unitRefId = $unitRefId; + return $this; + } + + /** + * @param GeographicalUnitLayer|null $layer + * @return GeographicalUnit + */ + public function setLayer(?GeographicalUnitLayer $layer): GeographicalUnit + { + $this->layer = $layer; return $this; } diff --git a/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepository.php b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepository.php new file mode 100644 index 000000000..ed259840b --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepository.php @@ -0,0 +1,57 @@ +repository = $em->getRepository($this->getClassName()); + $this->em = $em; + } + + + public function find($id): ?GeographicalUnit + { + return $this->repository->find($id); + } + + /** + * Will return only partial object, where the @link{GeographicalUnit::geom} property is not loaded + * + * @return array|GeographicalUnit[] + */ + public function findAll(): array + { + return $this->repository + ->createQueryBuilder('gu') + ->addSelect('PARTIAL gu.{id,unitName,unitRefId,layer}') + ->addOrderBy('IDENTITY(gu.layer)') + ->addOrderBy(('gu.unitName')) + ->getQuery() + ->getResult(); + } + + public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): ?GeographicalUnit + { + return $this->repository->findBy($criteria, $orderBy, $limit, $offset); + } + + public function findOneBy(array $criteria): ?GeographicalUnit + { + return $this->repository->findOneBy($criteria); + } + + public function getClassName(): string + { + return GeographicalUnit::class; + } +} \ No newline at end of file diff --git a/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepositoryInterface.php b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepositoryInterface.php new file mode 100644 index 000000000..10d07893b --- /dev/null +++ b/src/Bundle/ChillMainBundle/Repository/GeographicalUnitRepositoryInterface.php @@ -0,0 +1,10 @@ +em = $em; + $this->geographicalUnitRepository = $geographicalUnitRepository; + $this->translatableStringHelper = $translatableStringHelper; + } + public function addRole(): ?string { return null; @@ -42,33 +58,32 @@ class GeographicalUnitStatFilter implements FilterInterface public function alterQuery(QueryBuilder $qb, $data) { - if (!in_array('location', $qb->getAllAliases(), true)) { - $qb->join('acp.administrativeLocation', 'location'); - } + $subQueryDql = + 'SELECT + 1 + FROM '.AccompanyingPeriod\AccompanyingPeriodLocationHistory::class.' acp_geog_filter_location_history + LEFT JOIN '.PersonHouseholdAddress::class.' acp_geog_filter_address_person_location + WITH IDENTITY(acp_geog_filter_location_history.personLocation) = IDENTITY(acp_geog_filter_address_person_location.person) + LEFT JOIN '.Address::class.' acp_geog_filter_address + WITH COALESCE(IDENTITY(acp_geog_filter_address_person_location.address), IDENTITY(acp_geog_filter_location_history.addressLocation)) = acp_geog_filter_address.id + LEFT JOIN '.GeographicalUnit::class.' acp_geog_filter_units WITH ST_CONTAINS(acp_geog_units.geom, acp_geog_filter_address.point) = TRUE + WHERE + (acp_geog_filter_location_history.startDate <= :acp_geog_filter_date AND ( + acp_geog_filter_location_history.endDate IS NULL OR acp_geog_filter_location_history.endDate < :acp_geog_filter_date + )) + AND + (acp_geog_filter_address_person_location.validFrom < :acp_geog_filter_date AND ( + acp_geog_filter_address_person_location.validTo IS NULL OR acp_geog_filter_address_person_location.validTo < :acp_geog_filter_date + )) + AND acp_geog_filter_units IN (:acp_geog_filter_units) + AND acp_geog_filter_location_history.period = acp.id + '; - if (!in_array('address', $qb->getAllAliases(), true)) { - $qb->join('location.address', 'address'); - } - - if (!in_array('geounit', $qb->getAllAliases(), true)) { - $qb->join(GeographicalUnit::class, 'geounit', Expr\Join::WITH, 'ST_CONTAINS(address.point, geounit.geom) = TRUE'); - } - - $where = $qb->getDQLPart('where'); - $clause = $qb->expr()->andX( - $qb->expr()->eq($x, ':date'), - $qb->expr()->in($x, ':loctype') - ); - - if ($where instanceof Andx) { - $where->add($clause); - } else { - $where = $qb->expr()->andX($clause); - } - - $qb->add('where', $where); - $qb->setParameter('date', $data['date'], Types::DATE_MUTABLE); - $qb->setParameter('loctype', $data['accepted_loctype']); + $qb + ->andWhere($qb->expr()->exists($subQueryDql)) + ->setParameter('acp_geog_filter_date', $data['date_calc']) + ->setParameter('acp_geog_filter_units', $data['units']) + ; } public function applyOn(): string @@ -79,23 +94,40 @@ class GeographicalUnitStatFilter implements FilterInterface public function buildForm(FormBuilderInterface $builder) { $builder - ->add('date', ChillDateType::class, [ - 'data' => new DateTime(), + ->add('date_calc', ChillDateType::class, [ + 'label' => 'Compute geographical location at date', + 'required' => true, + 'data' => new \DateTimeImmutable('today'), + 'input' => 'datetime_immutable', ]) - ->add('accepted_loctype', EntityType::class, [ + ->add('units', EntityType::class, [ + 'label' => 'Geographical unit', + 'placeholder' => 'Select a geographical unit', 'class' => GeographicalUnit::class, - 'choice_label' => static function (GeographicalUnit $u) { - return $u->getUnitName(); + 'choices' => $this->geographicalUnitRepository->findAll(), + 'choice_label' => function(GeographicalUnit $item) { + return $this->translatableStringHelper->localize($item->getLayer()->getName()) . ' > ' . $item->getUnitName(); }, + 'attr' => [ + 'class' => 'select2', + ], 'multiple' => true, - 'expanded' => true, ]); } public function describeAction($data, $format = 'string'): array { - return ['Filtered by geographic unit: only %date%', [ - '%date%' => $data['date']->format('d-m-Y'), + return ['Filtered by geographic unit: computed at %date%, only in %units%', [ + '%date%' => $data['date_calc']->format('d-m-Y'), + '%units' => implode( + ', ', + array_map( + function(GeographicalUnit $item) { + return $this->translatableStringHelper->localize($item->getLayer()->getName()) . ' > ' . $item->getUnitName(); + }, + $data['units'] + ) + ) ]]; }