Bootstrap encoder for documents

This commit is contained in:
2021-11-22 09:05:15 +00:00
parent 46a4afe1b3
commit d0bf47e0d5
25 changed files with 992 additions and 91 deletions

View File

@@ -1139,11 +1139,11 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
public function getGroupSequence()
{
if ($this->getStep() == self::STEP_DRAFT) {
if ($this->getStep() == self::STEP_DRAFT)
{
return [[self::STEP_DRAFT]];
}
if ($this->getStep() == self::STEP_CONFIRMED) {
} elseif ($this->getStep() == self::STEP_CONFIRMED)
{
return [[self::STEP_DRAFT, self::STEP_CONFIRMED]];
}

View File

@@ -37,20 +37,20 @@ class MaritalStatus
* @ORM\Id()
* @ORM\Column(type="string", length=7)
*/
private $id;
private ?string $id;
/**
* @var string array
* @ORM\Column(type="json")
*/
private $name;
private array $name;
/**
* Get id
*
* @return string
*/
public function getId()
public function getId(): string
{
return $this->id;
}
@@ -61,7 +61,7 @@ class MaritalStatus
* @param string $id
* @return MaritalStatus
*/
public function setId($id)
public function setId(string $id): self
{
$this->id = $id;
return $this;
@@ -73,7 +73,7 @@ class MaritalStatus
* @param string array $name
* @return MaritalStatus
*/
public function setName($name)
public function setName(array $name): self
{
$this->name = $name;
@@ -85,7 +85,7 @@ class MaritalStatus
*
* @return string array
*/
public function getName()
public function getName(): array
{
return $this->name;
}

View File

@@ -219,7 +219,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
* groups={"general", "creation"}
* )
*/
private ?\DateTime $maritalStatusDate;
private ?\DateTime $maritalStatusDate = null;
/**
* Comment on marital status
@@ -252,7 +252,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
* The person's phonenumber
* @var string
*
* @ORM\Column(type="text", length=40, nullable=true)
* @ORM\Column(type="text")
* @Assert\Regex(
* pattern="/^([\+{1}])([0-9\s*]{4,20})$/",
* groups={"general", "creation"}
@@ -262,13 +262,13 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
* groups={"general", "creation"}
* )
*/
private $phonenumber = '';
private string $phonenumber = '';
/**
* The person's mobile phone number
* @var string
*
* @ORM\Column(type="text", length=40, nullable=true)
* @ORM\Column(type="text")
* @Assert\Regex(
* pattern="/^([\+{1}])([0-9\s*]{4,20})$/",
* groups={"general", "creation"}
@@ -278,7 +278,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
* groups={"general", "creation"}
* )
*/
private $mobilenumber = '';
private string $mobilenumber = '';
/**
* @var Collection
@@ -1094,9 +1094,9 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
/**
* Get nationality
*
* @return Chill\MainBundle\Entity\Country
* @return Country
*/
public function getNationality()
public function getNationality(): ?Country
{
return $this->nationality;
}
@@ -1176,7 +1176,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
*
* @return string
*/
public function getPhonenumber()
public function getPhonenumber(): string
{
return $this->phonenumber;
}
@@ -1199,7 +1199,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
*
* @return string
*/
public function getMobilenumber()
public function getMobilenumber(): string
{
return $this->mobilenumber;
}

View File

@@ -0,0 +1,116 @@
<?php
namespace Chill\PersonBundle\Serializer\Normalizer;
use Chill\DocGeneratorBundle\Serializer\Helper\NormalizeNullValueHelper;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\PersonAltName;
use Chill\PersonBundle\Templating\Entity\PersonRender;
use Symfony\Component\Serializer\Exception\CircularReferenceException;
use Symfony\Component\Serializer\Exception\ExceptionInterface;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class PersonDocGenNormalizer implements
ContextAwareNormalizerInterface,
NormalizerAwareInterface
{
use NormalizerAwareTrait;
private PersonRender $personRender;
private TranslatorInterface $translator;
private TranslatableStringHelper $translatableStringHelper;
/**
* @param PersonRender $personRender
* @param TranslatorInterface $translator
* @param TranslatableStringHelper $translatableStringHelper
*/
public function __construct(
PersonRender $personRender,
TranslatorInterface $translator,
TranslatableStringHelper $translatableStringHelper
) {
$this->personRender = $personRender;
$this->translator = $translator;
$this->translatableStringHelper = $translatableStringHelper;
}
public function normalize($person, string $format = null, array $context = [])
{
/** @var Person $person */
$dateContext = $context;
$dateContext['docgen:expects'] = \DateTimeInterface::class;
if (null === $person) {
return $this->normalizeNullValue($format, $context);
}
return [
'firstname' => $person->getFirstName(),
'lastname' => $person->getLastName(),
'altNames' => \implode(
', ',
\array_map(
function (PersonAltName $altName) {
return $altName->getLabel();
},
$person->getAltNames()->toArray()
)
),
'text' => $this->personRender->renderString($person, []),
'birthdate' => $this->normalizer->normalize($person->getBirthdate(), $format, $dateContext),
'deathdate' => $this->normalizer->normalize($person->getDeathdate(), $format, $dateContext),
'gender' => $this->translator->trans($person->getGender()),
'maritalStatus' => null !== ($ms = $person->getMaritalStatus()) ? $this->translatableStringHelper->localize($ms->getName()) : '',
'maritalStatusDate' => $this->normalizer->normalize($person->getMaritalStatusDate(), $format, $dateContext),
'email' => $person->getEmail(),
'firstPhoneNumber' => $person->getPhonenumber() ?? $person->getMobilenumber(),
'fixPhoneNumber' => $person->getPhonenumber(),
'mobilePhoneNumber' => $person->getMobilenumber(),
'nationality' => null !== ($c = $person->getNationality()) ? $this->translatableStringHelper->localize($c->getName()) : '',
'placeOfBirth' => $person->getPlaceOfBirth(),
'memo' => $person->getMemo(),
'numberOfChildren' => (string) $person->getNumberOfChildren(),
];
}
private function normalizeNullValue(string $format, array $context)
{
$normalizer = new NormalizeNullValueHelper($this->normalizer);
$attributes = [
'firstname', 'lastname', 'altNames', 'text',
'birthdate' => \DateTimeInterface::class,
'deathdate' => \DateTimeInterface::class,
'gender', 'maritalStatus',
'maritalStatusDate' => \DateTimeInterface::class,
'email', 'firstPhoneNumber', 'fixPhoneNumber', 'mobilePhoneNumber', 'nationality',
'placeOfBirth', 'memo', 'numberOfChildren'
];
return $normalizer->normalize($attributes, $format, $context);
}
public function supportsNormalization($data, string $format = null, array $context = [])
{
if ($format !== 'docgen') {
return false;
}
return
$data instanceof Person
|| (
\array_key_exists('docgen:expects', $context)
&& $context['docgen:expects'] === Person::class
);
}
}

View File

@@ -39,7 +39,7 @@ use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;
* Serialize a Person entity
*
*/
class PersonNormalizer implements
class PersonJsonNormalizer implements
NormalizerInterface,
NormalizerAwareInterface,
DenormalizerInterface,
@@ -105,7 +105,7 @@ class PersonNormalizer implements
public function supportsNormalization($data, string $format = null): bool
{
return $data instanceof Person;
return $data instanceof Person && $format === 'json';
}
public function denormalize($data, string $type, string $format = null, array $context = [])
@@ -128,45 +128,48 @@ class PersonNormalizer implements
$person = new Person();
}
$properties = ['firstName', 'lastName', 'phonenumber', 'mobilenumber', 'gender'];
foreach (['firstName', 'lastName', 'phonenumber', 'mobilenumber', 'gender',
'birthdate', 'deathdate', 'center']
as $item) {
$properties = array_filter(
$properties,
static fn (string $property): bool => array_key_exists($property, $data)
);
foreach ($properties as $item) {
$callable = [$person, sprintf('set%s', ucfirst($item))];
if (is_callable($callable)) {
$closure = \Closure::fromCallable($callable);
$closure($data[$item]);
if (!\array_key_exists($item, $data)) {
continue;
}
}
$propertyToClassMapping = [
'birthdate' => \DateTime::class,
'deathdate' => \DateTime::class,
'center' => Center::class,
];
$propertyToClassMapping = array_filter(
$propertyToClassMapping,
static fn (string $item): bool => array_key_exists($item, $data)
);
foreach ($propertyToClassMapping as $item => $class) {
$object = $this->denormalizer->denormalize($data[$item], $class, $format, $context);
if ($object instanceof $class) {
$callable = [$object, sprintf('set%s', ucfirst($item))];
if (is_callable($callable)) {
$closure = \Closure::fromCallable($callable);
$closure($object);
}
switch ($item) {
case 'firstName':
$person->setFirstName($data[$item]);
break;
case 'lastName':
$person->setLastName($data[$item]);
break;
case 'phonenumber':
$person->setPhonenumber($data[$item]);
break;
case 'mobilenumber':
$person->setMobilenumber($data[$item]);
break;
case 'gender':
$person->setGender($data[$item]);
break;
case 'birthdate':
$object = $this->denormalizer->denormalize($data[$item], \DateTime::class, $format, $context);
if ($object instanceof \DateTime) {
$person->setBirthdate($object);
}
break;
case 'deathdate':
$object = $this->denormalizer->denormalize($data[$item], \DateTime::class, $format, $context);
if ($object instanceof \DateTime) {
$person->setDeathdate($object);
}
break;
case 'center':
$object = $this->denormalizer->denormalize($data[$item], Center::class, $format, $context);
$person->setCenter($object);
break;
default:
throw new \LogicException("item not defined: $item");
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace Serializer\Normalizer;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Entity\PersonAltName;
use Chill\PersonBundle\Serializer\Normalizer\PersonDocGenNormalizer;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class PersonDocGenNormalizerTest extends KernelTestCase
{
private NormalizerInterface $normalizer;
protected function setUp()
{
self::bootKernel();
$this->normalizer = self::$container->get(NormalizerInterface::class);
}
/**
* @dataProvider generateData
*/
public function testNormalize(?Person $person, $expected, $msg)
{
$normalized = $this->normalizer->normalize($person, 'docgen', ['docgen:expects' => Person::class]);
$this->assertEquals($expected, $normalized, $msg);
}
public function generateData()
{
$person = new Person();
$person
->setFirstName('Renaud')
->setLastName('Mégane')
;
$expected = \array_merge(
self::BLANK, ['firstname' => 'Renaud', 'lastname' => 'Mégane',
'text' => 'Renaud Mégane']
);
yield [$person, $expected, 'partial normalization for a person'];
yield [null, self::BLANK, 'normalization for a null person'];
}
private const BLANK = [
'firstname' => '',
'lastname' => '',
'altNames' => '',
'text' => '',
'birthdate' => ['short' => '', 'long' => ''],
'deathdate' => ['short' => '', 'long' => ''],
'gender' => '',
'maritalStatus' => '',
'maritalStatusDate' => ['short' => '', 'long' => ''],
'email' => '',
'firstPhoneNumber' => '',
'fixPhoneNumber' => '',
'mobilePhoneNumber' => '',
'nationality' => '',
'placeOfBirth' => '',
'memo' => '',
'numberOfChildren' => ''
];
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Serializer\Normalizer;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Serializer\Normalizer\PersonJsonNormalizer;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class PersonJsonNormalizerTest extends KernelTestCase
{
private NormalizerInterface $normalizer;
protected function setUp()
{
self::bootKernel();
$this->normalizer = self::$container->get(NormalizerInterface::class);
}
public function testNormalization()
{
$person = new Person();
$result = $this->normalizer->normalize($person, 'json', [AbstractNormalizer::GROUPS => [ 'read' ]]);
$this->assertIsArray($result);
}
}

View File

@@ -4,6 +4,7 @@ services:
Chill\PersonBundle\Serializer\Normalizer\:
autowire: true
autoconfigure: true
resource: '../../Serializer/Normalizer'
tags:
- { name: 'serializer.normalizer', priority: 64 }

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Chill\Migrations\Person;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* drop not null in person phonenumber
*/
final class Version20211112170027 extends AbstractMigration
{
public function getDescription(): string
{
return 'Drop not null in person table: set default empty value';
}
public function up(Schema $schema): void
{
$this->addSql('UPDATE chill_person_person SET mobilenumber = \'\' WHERE mobilenumber IS NULL');
$this->addSql('UPDATE chill_person_person SET phonenumber = \'\' WHERE phonenumber IS NULL');
$this->addSql('ALTER TABLE chill_person_person ALTER mobilenumber SET NOT NULL');
$this->addSql('ALTER TABLE chill_person_person ALTER phonenumber SET NOT NULL');
$this->addSql('ALTER TABLE chill_person_person ALTER mobilenumber SET DEFAULT \'\'');
$this->addSql('ALTER TABLE chill_person_person ALTER phonenumber SET DEFAULT \'\'');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE chill_person_person ALTER mobilenumber DROP NOT NULL');
$this->addSql('ALTER TABLE chill_person_person ALTER phonenumber DROP NOT NULL');
$this->addSql('ALTER TABLE chill_person_person ALTER mobilenumber SET DEFAULT NULL');
$this->addSql('ALTER TABLE chill_person_person ALTER phonenumber SET DEFAULT NULL');
}
}