275 lines
9.2 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\Repository\AddressRepository;
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 in_array;
use function strlen;
/**
* Helps to load addresses and format them in list.
*/
class ExportAddressHelper
{
public const F_ALL =
self::F_ATTRIBUTES | self::F_BUILDING | self::F_COUNTRY |
self::F_GEOM | self::F_POSTAL_CODE | self::F_STREET;
public const F_AS_STRING = 0b00010000;
public const F_ATTRIBUTES = 0b01000000;
public const F_BUILDING = 0b00001000;
public const F_COUNTRY = 0b00000001;
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,
];
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'],
];
private AddressRender $addressRender;
private AddressRepository $addressRepository;
private PropertyAccessor $propertyAccess;
private TranslatableStringHelperInterface $translatableStringHelper;
public function __construct(
AddressRepository $addressRepository,
TranslatableStringHelperInterface $translatableStringHelper,
AddressRender $addressRender
) {
$this->addressRepository = $addressRepository;
$this->propertyAccess = PropertyAccess::createPropertyAccessor();
$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;
default:
throw new LogicException('This key is not supported: ' . $key);
}
}
}
}
}
/**
* @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) {
$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 '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:
throw new LogicException('this key is not supported: ' . $sanitizedKey);
}
}
}