Fixed: [export][list person] use address from household for person list

This commit is contained in:
2022-10-25 10:23:02 +02:00
parent 4af261a366
commit 333c305eef
6 changed files with 515 additions and 237 deletions

View File

@@ -17,28 +17,33 @@ use Chill\CustomFieldsBundle\Service\CustomFieldProvider;
use Chill\MainBundle\Export\ExportElementValidatedInterface;
use Chill\MainBundle\Export\FormatterInterface;
use Chill\MainBundle\Export\GroupedExportInterface;
use Chill\MainBundle\Export\Helper\ExportAddressHelper;
use Chill\MainBundle\Export\ListInterface;
use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Repository\CountryRepository;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Export\Declarations;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use DateTime;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Exception;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use function addcslashes;
use function array_key_exists;
use function array_keys;
use function array_merge;
use function count;
use function in_array;
use function strlen;
use function strtolower;
use function uniqid;
@@ -47,31 +52,40 @@ use function uniqid;
*/
class ListPerson implements ExportElementValidatedInterface, ListInterface, GroupedExportInterface
{
protected CustomFieldProvider $customFieldProvider;
protected EntityManagerInterface $entityManager;
protected array $fields = [
'id', 'firstName', 'lastName', 'birthdate',
public const FIELDS = [
'id',
'firstName',
'lastName',
'birthdate',
'placeOfBirth', 'gender', 'memo', 'email', 'phonenumber',
'mobilenumber', 'contactInfo', 'countryOfBirth', 'nationality',
'address_street_address_1', 'address_street_address_2',
'address_valid_from', 'address_postcode_label', 'address_postcode_code',
'address_country_name', 'address_country_code', 'address_isnoaddress',
'address',
];
protected TranslatableStringHelper $translatableStringHelper;
private ExportAddressHelper $addressHelper;
protected TranslatorInterface $translator;
private CountryRepository $countryRepository;
private CustomFieldProvider $customFieldProvider;
private EntityManagerInterface $entityManager;
private $slugs = [];
private TranslatableStringHelper $translatableStringHelper;
private TranslatorInterface $translator;
public function __construct(
CountryRepository $countryRepository,
ExportAddressHelper $addressHelper,
EntityManagerInterface $em,
TranslatorInterface $translator,
TranslatableStringHelper $translatableStringHelper,
CustomFieldProvider $customFieldProvider
) {
$this->addressHelper = $addressHelper;
$this->countryRepository = $countryRepository;
$this->entityManager = $em;
$this->translator = $translator;
$this->translatableStringHelper = $translatableStringHelper;
@@ -80,7 +94,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
public function buildForm(FormBuilderInterface $builder)
{
$choices = array_combine($this->fields, $this->fields);
$choices = array_combine(self::FIELDS, self::FIELDS);
foreach ($this->getCustomFields() as $cf) {
$choices[$this->translatableStringHelper->localize($cf->getName())]
@@ -96,7 +110,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
'label' => 'Fields to include in export',
'choice_attr' => static function (string $val): array {
// add a 'data-display-target' for address fields
if (substr($val, 0, 8) === 'address_') {
if (substr($val, 0, 7) === 'address') {
return ['data-display-target' => 'address_date'];
}
@@ -111,17 +125,14 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
}
},
])],
'data' => array_values($choices),
]);
// add a date field for addresses
$builder->add('address_date', DateType::class, [
$builder->add('address_date', ChillDateType::class, [
'label' => 'Address valid at this date',
'data' => new DateTime(),
'attr' => ['class' => 'datepicker'],
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
'required' => false,
'block_name' => 'list_export_form_address_date',
'data' => new DateTimeImmutable(),
'input' => 'datetime_immutable',
]);
}
@@ -142,6 +153,10 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
public function getLabels($key, array $values, $data)
{
if (substr($key, 0, strlen('address')) === 'address') {
return $this->addressHelper->getLabel($key, $values, $data, 'address_');
}
switch ($key) {
case 'birthdate':
// for birthdate, we have to transform the string into a date
@@ -151,10 +166,11 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
return 'birthdate';
}
if (empty($value)) {
if (null === $value) {
return '';
}
// warning: won't work with DateTimeImmutable as we reset time a few lines later
$date = DateTime::createFromFormat('Y-m-d', $value);
// check that the creation could occurs.
if (false === $date) {
@@ -162,7 +178,9 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
. 'not be converted to %s', $value, DateTime::class));
}
return $date->format('d-m-Y');
$date->setTime(0, 0, 0);
return $date;
};
case 'gender':
@@ -177,29 +195,6 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
case 'countryOfBirth':
case 'nationality':
$countryRepository = $this->entityManager
->getRepository(\Chill\MainBundle\Entity\Country::class);
// load all countries in a single query
$countryRepository->findBy(['countryCode' => $values]);
return function ($value) use ($key, $countryRepository) {
if ('_header' === $value) {
return strtolower($key);
}
if (null === $value) {
return $this->translator->trans('no data');
}
$country = $countryRepository->find($value);
return $this->translatableStringHelper->localize(
$country->getName()
);
};
case 'address_country_name':
return function ($value) use ($key) {
if ('_header' === $value) {
return strtolower($key);
@@ -209,25 +204,16 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
return '';
}
return $this->translatableStringHelper->localize(json_decode($value, true));
};
$country = $this->countryRepository->find($value);
case 'address_isnoaddress':
return static function (?string $value): string {
if ('_header' === $value) {
return 'address.address_homeless';
}
if (null !== $value) {
return 'X';
}
return '';
return $this->translatableStringHelper->localize(
$country->getName()
);
};
default:
// for fields which are associated with person
if (in_array($key, $this->fields, true)) {
if (in_array($key, self::FIELDS, true)) {
return static function ($value) use ($key) {
if ('_header' === $value) {
return strtolower($key);
@@ -246,9 +232,13 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
$fields = [];
foreach ($data['fields'] as $key) {
if (in_array($key, $this->fields, true)) {
$fields[] = $key;
if (substr($key, 0, strlen('address')) === 'address') {
$fields = array_merge($fields, $this->addressHelper->getKeys(0b01111111, 'address_'));
continue;
}
$fields[] = $key;
}
// add the key from slugs and return
@@ -270,6 +260,9 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
return Declarations::PERSON_TYPE;
}
/**
* @param array{fields: string[], address_date: DateTimeImmutable} $data
*/
public function initiateQuery(array $requiredModifiers, array $acl, array $data = [])
{
$centers = array_map(static function ($el) {
@@ -284,36 +277,57 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
$qb = $this->entityManager->createQueryBuilder();
foreach ($this->fields as $f) {
if (in_array($f, $data['fields'], true)) {
switch ($f) {
case 'countryOfBirth':
case 'nationality':
$qb->addSelect(sprintf('IDENTITY(person.%s) as %s', $f, $f));
$qb
->from(Person::class, 'person')
->andWhere(
$qb->expr()->exists(
'SELECT 1 FROM ' . Person\PersonCenterHistory::class . ' pch WHERE pch.person = person.id AND pch.center IN (:authorized_centers)'
)
)
->setParameter('authorized_centers', $centers);
break;
foreach (self::FIELDS as $f) {
if (!in_array($f, $data['fields'], true)) {
continue;
}
case 'address_street_address_1':
case 'address_street_address_2':
case 'address_valid_from':
case 'address_postcode_label':
case 'address_postcode_code':
case 'address_country_name':
case 'address_country_code':
case 'address_isnoaddress':
$qb->addSelect(sprintf(
'GET_PERSON_ADDRESS_%s(person.id, :address_date) AS %s',
// get the part after address_
strtoupper(substr($f, 8)),
$f
));
$qb->setParameter('address_date', $data['address_date']);
switch ($f) {
case 'countryOfBirth':
case 'nationality':
$qb->addSelect(sprintf('IDENTITY(person.%s) as %s', $f, $f));
break;
break;
default:
$qb->addSelect(sprintf('person.%s as %s', $f, $f));
}
case 'address':
foreach ($this->addressHelper->getKeys(0b01111111, 'address_') as $key) {
$qb
->addSelect(sprintf('IDENTITY(currentPersonAddress.address) AS %s', $key));
}
if (!(in_array('currentPersonAddress', $qb->getAllAliases(), true))) {
$qb
->leftJoin('person.currentPersonAddress', 'currentPersonAddress')
->andWhere(
$qb->expr()->orX(
// no address at this time
$qb->expr()->isNull('currentPersonAddress'),
// there is one address...
$qb->expr()->andX(
$qb->expr()->lte('currentPersonAddress.validFrom', ':address_date'),
$qb->expr()->orX(
$qb->expr()->isNull('currentPersonAddress.validTo'),
$qb->expr()->gt('currentPersonAddress.validTo', ':address_date')
)
)
)
)
->setParameter('address_date', $data['address_date']);
}
break;
default:
$qb->addSelect(sprintf('person.%s as %s', $f, $f));
}
}
@@ -345,12 +359,6 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
}
}
$qb
->from('ChillPersonBundle:Person', 'person')
->join('person.center', 'center')
->andWhere('center IN (:authorized_centers)')
->setParameter('authorized_centers', $centers);
return $qb;
}
@@ -368,7 +376,7 @@ class ListPerson implements ExportElementValidatedInterface, ListInterface, Grou
{
// get the field starting with address_
$addressFields = array_filter(
$this->fields,
self::FIELDS,
static fn (string $el): bool => substr($el, 0, 8) === 'address_'
);