From 434ef075da9d3ccf8cf1903532bdc684b6ff3da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 14 Nov 2022 17:06:26 +0100 Subject: [PATCH] Feature: Add geographical unit name and ref ids in list, associated to address --- .../Export/Helper/ExportAddressHelper.php | 165 +++++++++++++++++- 1 file changed, 157 insertions(+), 8 deletions(-) diff --git a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php index 701f9ed07..9077b501a 100644 --- a/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php +++ b/src/Bundle/ChillMainBundle/Export/Helper/ExportAddressHelper.php @@ -11,13 +11,16 @@ declare(strict_types=1); namespace Chill\MainBundle\Export\Helper; +use Chill\MainBundle\Entity\GeographicalUnit; +use Chill\MainBundle\Entity\GeographicalUnitLayer; use Chill\MainBundle\Repository\AddressRepository; +use Chill\MainBundle\Repository\GeographicalUnitLayerRepositoryInterface; use Chill\MainBundle\Templating\Entity\AddressRender; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; use Doctrine\ORM\QueryBuilder; use LogicException; -use Symfony\Component\PropertyAccess\PropertyAccess; -use Symfony\Component\PropertyAccess\PropertyAccessor; +use function array_key_exists; +use function count; use function in_array; use function strlen; @@ -26,9 +29,12 @@ use function strlen; */ class ExportAddressHelper { + /** + * Compute all the F_* constants. + */ public const F_ALL = self::F_ATTRIBUTES | self::F_BUILDING | self::F_COUNTRY | - self::F_GEOM | self::F_POSTAL_CODE | self::F_STREET; + self::F_GEOM | self::F_POSTAL_CODE | self::F_STREET | self::F_GEOGRAPHICAL_UNITS; public const F_AS_STRING = 0b00010000; @@ -38,6 +44,8 @@ class ExportAddressHelper public const F_COUNTRY = 0b00000001; + public const F_GEOGRAPHICAL_UNITS = 0b1000000000; + public const F_GEOM = 0b00100000; public const F_POSTAL_CODE = 0b00000010; @@ -52,6 +60,7 @@ class ExportAddressHelper 'string' => self::F_AS_STRING, 'geom' => self::F_GEOM, 'attributes' => self::F_ATTRIBUTES, + 'geographical_units' => self::F_GEOGRAPHICAL_UNITS, ]; private const COLUMN_MAPPING = [ @@ -62,23 +71,35 @@ class ExportAddressHelper 'string' => ['_as_string'], 'attributes' => ['isNoAddress', 'confidential', 'id'], 'geom' => ['_lat', '_lon'], + 'geographical_units' => ['_unit_names', '_unit_refs'], ]; private AddressRender $addressRender; private AddressRepository $addressRepository; - private PropertyAccessor $propertyAccess; + private GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository; private TranslatableStringHelperInterface $translatableStringHelper; + /** + * @var array>|null + */ + private ?array $unitNamesKeysCache = []; + + /** + * @var array>|null + */ + private ?array $unitRefsKeysCache = []; + public function __construct( + AddressRender $addressRender, AddressRepository $addressRepository, - TranslatableStringHelperInterface $translatableStringHelper, - AddressRender $addressRender + GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository, + TranslatableStringHelperInterface $translatableStringHelper ) { $this->addressRepository = $addressRepository; - $this->propertyAccess = PropertyAccess::createPropertyAccessor(); + $this->geographicalUnitLayerRepository = $geographicalUnitLayerRepository; $this->translatableStringHelper = $translatableStringHelper; $this->addressRender = $addressRender; } @@ -155,8 +176,60 @@ class ExportAddressHelper break; + case '_unit_names': + foreach ($this->generateKeysForUnitsNames($prefix) as $alias => $layer) { + $queryBuilder + ->addSelect( + sprintf( + '(SELECT AGGREGATE(u_n_%s_%s.unitName) FROM %s u_n_%s_%s WHERE u_n_%s_%s MEMBER OF %s.geographicalUnits AND u_n_%s_%s.layer = :layer_%s_%s) AS %s', + $prefix, + $layer->getId(), + GeographicalUnit::class, + $prefix, + $layer->getId(), + $prefix, + $layer->getId(), + $entityName, + $prefix, + $layer->getId(), + $prefix, + $layer->getId(), + $alias + ) + ) + ->setParameter(sprintf('layer_%s_%s', $prefix, $layer->getId()), $layer); + } + + break; + + case '_unit_refs': + foreach ($this->generateKeysForUnitsRefs($prefix) as $alias => $layer) { + $queryBuilder + ->addSelect( + sprintf( + '(SELECT AGGREGATE(u_r_%s_%s.unitRefId) FROM %s u_r_%s_%s WHERE u_r_%s_%s MEMBER OF %s.geographicalUnits AND u_r_%s_%s.layer = :layer_%s_%s) AS %s', + $prefix, + $layer->getId(), + GeographicalUnit::class, + $prefix, + $layer->getId(), + $prefix, + $layer->getId(), + $entityName, + $prefix, + $layer->getId(), + $prefix, + $layer->getId(), + $alias + ) + ) + ->setParameter(sprintf('layer_%s_%s', $prefix, $layer->getId()), $layer); + } + + break; + default: - throw new LogicException('This key is not supported: ' . $key); + throw new LogicException(sprintf('This key is not supported: %s, field %s', $key, $field)); } } } @@ -174,6 +247,13 @@ class ExportAddressHelper foreach (self::ALL as $key => $bitmask) { if (($params & $bitmask) === $bitmask) { + if ('geographical_units' === $key) { + // geographical unit generate keys dynamically, depending on layers + $prefixes = array_merge($prefixes, array_keys($this->generateKeysForUnitsNames($prefix)), array_keys($this->generateKeysForUnitsRefs($prefix))); + + continue; + } + $prefixes = array_merge( $prefixes, array_map( @@ -271,7 +351,76 @@ class ExportAddressHelper }; default: + $layerNamesKeys = array_merge($this->generateKeysForUnitsNames($prefix), $this->generateKeysForUnitsRefs($prefix)); + + if (array_key_exists($key, $layerNamesKeys)) { + return function ($value) use ($key, $layerNamesKeys) { + if ('_header' === $value) { + $header = $this->translatableStringHelper->localize($layerNamesKeys[$key]->getName()); + + if (str_contains($key, 'unit_ref')) { + $header .= ' (id)'; + } + + return $header; + } + + if (null === $value) { + return ''; + } + + $decodedValues = json_decode($value, true); + + switch (count($decodedValues)) { + case 0: + return ''; + + case 1: + return $decodedValues[0]; + + default: + return implode('|', $decodedValues); + } + }; + } + throw new LogicException('this key is not supported: ' . $sanitizedKey); } } + + /** + * @return array + */ + private function generateKeysForUnitsNames(string $prefix): array + { + if (array_key_exists($prefix, $this->unitNamesKeysCache)) { + return $this->unitNamesKeysCache[$prefix]; + } + + $keys = []; + + foreach ($this->geographicalUnitLayerRepository->findAllHavingUnits() as $layer) { + $keys[$prefix . 'unit_names_' . $layer->getId()] = $layer; + } + + return $this->unitNamesKeysCache[$prefix] = $keys; + } + + /** + * @return array + */ + private function generateKeysForUnitsRefs(string $prefix): array + { + if (array_key_exists($prefix, $this->unitRefsKeysCache)) { + return $this->unitRefsKeysCache[$prefix]; + } + + $keys = []; + + foreach ($this->geographicalUnitLayerRepository->findAllHavingUnits() as $layer) { + $keys[$prefix . 'unit_refs_' . $layer->getId()] = $layer; + } + + return $this->unitRefsKeysCache[$prefix] = $keys; + } }