mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-20 22:53:49 +00:00
427 lines
16 KiB
PHP
427 lines
16 KiB
PHP
<?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\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 function array_key_exists;
|
|
use function count;
|
|
use function in_array;
|
|
use function strlen;
|
|
|
|
/**
|
|
* Helps to load addresses and format them in list.
|
|
*/
|
|
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_GEOGRAPHICAL_UNITS;
|
|
|
|
public const F_AS_STRING = 0b00010000;
|
|
|
|
public const F_ATTRIBUTES = 0b01000000;
|
|
|
|
public const F_BUILDING = 0b00001000;
|
|
|
|
public const F_COUNTRY = 0b00000001;
|
|
|
|
public const F_GEOGRAPHICAL_UNITS = 0b1000000000;
|
|
|
|
public const F_GEOM = 0b00100000;
|
|
|
|
public const F_POSTAL_CODE = 0b00000010;
|
|
|
|
public const F_STREET = 0b00000100;
|
|
|
|
private const ALL = [
|
|
'country' => self::F_COUNTRY,
|
|
'postal_code' => self::F_POSTAL_CODE,
|
|
'street' => self::F_STREET,
|
|
'building' => self::F_BUILDING,
|
|
'string' => self::F_AS_STRING,
|
|
'geom' => self::F_GEOM,
|
|
'attributes' => self::F_ATTRIBUTES,
|
|
'geographical_units' => self::F_GEOGRAPHICAL_UNITS,
|
|
];
|
|
|
|
private const COLUMN_MAPPING = [
|
|
'country' => ['country'],
|
|
'postal_code' => ['postcode_code', 'postcode_name'],
|
|
'street' => ['street', 'streetNumber'],
|
|
'building' => ['buildingName', 'corridor', 'distribution', 'extra', 'flat', 'floor', 'steps'],
|
|
'string' => ['_as_string'],
|
|
'attributes' => ['isNoAddress', 'confidential', 'id'],
|
|
'geom' => ['_lat', '_lon'],
|
|
'geographical_units' => ['_unit_names', '_unit_refs'],
|
|
];
|
|
|
|
private AddressRender $addressRender;
|
|
|
|
private AddressRepository $addressRepository;
|
|
|
|
private GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository;
|
|
|
|
private TranslatableStringHelperInterface $translatableStringHelper;
|
|
|
|
/**
|
|
* @var array<string, string, GeographicalUnitLayer>>|null
|
|
*/
|
|
private ?array $unitNamesKeysCache = [];
|
|
|
|
/**
|
|
* @var array<string, array<string, GeographicalUnitLayer>>|null
|
|
*/
|
|
private ?array $unitRefsKeysCache = [];
|
|
|
|
public function __construct(
|
|
AddressRender $addressRender,
|
|
AddressRepository $addressRepository,
|
|
GeographicalUnitLayerRepositoryInterface $geographicalUnitLayerRepository,
|
|
TranslatableStringHelperInterface $translatableStringHelper
|
|
) {
|
|
$this->addressRepository = $addressRepository;
|
|
$this->geographicalUnitLayerRepository = $geographicalUnitLayerRepository;
|
|
$this->translatableStringHelper = $translatableStringHelper;
|
|
$this->addressRender = $addressRender;
|
|
}
|
|
|
|
public function addSelectClauses(int $params, QueryBuilder $queryBuilder, $entityName = 'address', $prefix = 'add')
|
|
{
|
|
foreach (self::ALL as $key => $bitmask) {
|
|
if (($params & $bitmask) === $bitmask) {
|
|
foreach (self::COLUMN_MAPPING[$key] as $field) {
|
|
switch ($field) {
|
|
case 'id':
|
|
case '_as_string':
|
|
$queryBuilder->addSelect(sprintf('%s.id AS %s%s', $entityName, $prefix, $field));
|
|
|
|
break;
|
|
|
|
case 'street':
|
|
case 'streetNumber':
|
|
case 'floor':
|
|
case 'corridor':
|
|
case 'steps':
|
|
case 'buildingName':
|
|
case 'flat':
|
|
case 'distribution':
|
|
case 'extra':
|
|
$queryBuilder->addSelect(sprintf('%s.%s AS %s%s', $entityName, $field, $prefix, $field));
|
|
|
|
break;
|
|
|
|
case 'country':
|
|
case 'postcode_name':
|
|
case 'postcode_code':
|
|
$postCodeAlias = sprintf('%spostcode_t', $prefix);
|
|
|
|
if (!in_array($postCodeAlias, $queryBuilder->getAllAliases(), true)) {
|
|
$queryBuilder->leftJoin($entityName . '.postcode', $postCodeAlias);
|
|
}
|
|
|
|
if ('postcode_name' === $field) {
|
|
$queryBuilder->addSelect(sprintf('%s.%s AS %s%s', $postCodeAlias, 'name', $prefix, $field));
|
|
|
|
break;
|
|
}
|
|
|
|
if ('postcode_code' === $field) {
|
|
$queryBuilder->addSelect(sprintf('%s.%s AS %s%s', $postCodeAlias, 'code', $prefix, $field));
|
|
|
|
break;
|
|
}
|
|
|
|
$countryAlias = sprintf('%scountry_t', $prefix);
|
|
|
|
if (!in_array($countryAlias, $queryBuilder->getAllAliases(), true)) {
|
|
$queryBuilder->leftJoin(sprintf('%s.country', $postCodeAlias), $countryAlias);
|
|
}
|
|
|
|
$queryBuilder->addSelect(sprintf('%s.%s AS %s%s', $countryAlias, 'name', $prefix, $field));
|
|
|
|
break;
|
|
|
|
case 'isNoAddress':
|
|
case 'confidential':
|
|
$queryBuilder->addSelect(sprintf('CASE WHEN %s.%s = \'TRUE\' THEN 1 ELSE 0 END AS %s%s', $entityName, $field, $prefix, $field));
|
|
|
|
break;
|
|
|
|
case '_lat':
|
|
$queryBuilder->addSelect(sprintf('ST_Y(%s.point) AS %s%s', $entityName, $prefix, $field));
|
|
|
|
break;
|
|
|
|
case '_lon':
|
|
$queryBuilder->addSelect(sprintf('ST_X(%s.point) AS %s%s', $entityName, $prefix, $field));
|
|
|
|
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(sprintf('This key is not supported: %s, field %s', $key, $field));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param self::F_* $params
|
|
*
|
|
* @return array|string[]
|
|
*/
|
|
public function getKeys(int $params, string $prefix = ''): array
|
|
{
|
|
$prefixes = [];
|
|
|
|
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(
|
|
static function ($item) use ($prefix) {
|
|
return $prefix . $item;
|
|
},
|
|
self::COLUMN_MAPPING[$key]
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
return $prefixes;
|
|
}
|
|
|
|
public function getLabel($key, array $values, $data, string $prefix = '', string $translationPrefix = 'export.address_helper.'): callable
|
|
{
|
|
$sanitizedKey = substr($key, strlen($prefix));
|
|
|
|
switch ($sanitizedKey) {
|
|
case 'id':
|
|
case 'street':
|
|
case 'streetNumber':
|
|
case 'buildingName':
|
|
case 'corridor':
|
|
case 'distribution':
|
|
case 'extra':
|
|
case 'flat':
|
|
case 'floor':
|
|
case '_lat':
|
|
case '_lon':
|
|
case 'steps':
|
|
case 'postcode_code':
|
|
case 'postcode_name':
|
|
return static function ($value) use ($sanitizedKey, $translationPrefix) {
|
|
if ('_header' === $value) {
|
|
return $translationPrefix . $sanitizedKey;
|
|
}
|
|
|
|
if (null === $value) {
|
|
return '';
|
|
}
|
|
|
|
return $value;
|
|
};
|
|
|
|
case 'country':
|
|
return function ($value) use ($key) {
|
|
if ('_header' === $value) {
|
|
return 'export.list.acp' . $key;
|
|
}
|
|
|
|
if (null === $value) {
|
|
return '';
|
|
}
|
|
|
|
return $this->translatableStringHelper->localize(json_decode($value, true));
|
|
};
|
|
|
|
case 'isNoAddress':
|
|
case 'confidential':
|
|
return static function ($value) use ($sanitizedKey, $translationPrefix) {
|
|
if ('_header' === $value) {
|
|
return $translationPrefix . $sanitizedKey;
|
|
}
|
|
|
|
switch ($value) {
|
|
case null:
|
|
return '';
|
|
|
|
case true:
|
|
return 1;
|
|
|
|
case false:
|
|
return 0;
|
|
|
|
default:
|
|
throw new LogicException('this value is not supported for ' . $sanitizedKey . ': ' . $value);
|
|
}
|
|
};
|
|
|
|
case '_as_string':
|
|
return function ($value) use ($sanitizedKey, $translationPrefix) {
|
|
if ('_header' === $value) {
|
|
return $translationPrefix . $sanitizedKey;
|
|
}
|
|
|
|
if (null === $value) {
|
|
return '';
|
|
}
|
|
|
|
$address = $this->addressRepository->find($value);
|
|
|
|
return $this->addressRender->renderString($address, []);
|
|
};
|
|
|
|
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<string, GeographicalUnitLayer>
|
|
*/
|
|
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<string, GeographicalUnitLayer>
|
|
*/
|
|
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;
|
|
}
|
|
}
|