mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch 'features/docgen-normalization' into 'master'
Bootstrap encoder for documents See merge request Chill-Projet/chill-bundles!208
This commit is contained in:
commit
009a093b9d
@ -27,6 +27,7 @@ and this project adheres to
|
|||||||
* ajout d'un bouton "recherche avancée" sur la page d'accueil
|
* ajout d'un bouton "recherche avancée" sur la page d'accueil
|
||||||
* [person] create an accompanying course: add client-side validation if no origin (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/210)
|
* [person] create an accompanying course: add client-side validation if no origin (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/210)
|
||||||
* [person] fix bounds for computing current person address: the new address appears immediatly
|
* [person] fix bounds for computing current person address: the new address appears immediatly
|
||||||
|
* [docgen] create a normalizer and serializer for normalization on doc format
|
||||||
|
|
||||||
|
|
||||||
## Test releases
|
## Test releases
|
||||||
|
@ -91,7 +91,8 @@
|
|||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
"App\\": "tests/app/src/"
|
"App\\": "tests/app/src/",
|
||||||
|
"Chill\\DocGeneratorBundle\\Tests\\": "src/Bundle/ChillDocGeneratorBundle/tests"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimum-stability": "dev",
|
"minimum-stability": "dev",
|
||||||
|
@ -4,6 +4,7 @@ parameters:
|
|||||||
- src/
|
- src/
|
||||||
excludePaths:
|
excludePaths:
|
||||||
- src/Bundle/*/Tests/*
|
- src/Bundle/*/Tests/*
|
||||||
|
- src/Bundle/*/tests/*
|
||||||
- src/Bundle/*/Test/*
|
- src/Bundle/*/Test/*
|
||||||
- src/Bundle/*/config/*
|
- src/Bundle/*/config/*
|
||||||
- src/Bundle/*/migrations/*
|
- src/Bundle/*/migrations/*
|
||||||
|
@ -37,6 +37,9 @@
|
|||||||
<testsuite name="CalendarBundle">
|
<testsuite name="CalendarBundle">
|
||||||
<directory suffix="Test.php">src/Bundle/ChillCalendarBundle/Tests/</directory>
|
<directory suffix="Test.php">src/Bundle/ChillCalendarBundle/Tests/</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
|
<testsuite name="DocGeneratorBundle">
|
||||||
|
<directory suffix="Test.php">src/Bundle/ChillDocGeneratorBundle/tests/</directory>
|
||||||
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
<listeners>
|
<listeners>
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\DocGeneratorBundle\Serializer\Encoder;
|
||||||
|
|
||||||
|
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||||
|
|
||||||
|
class DocGenEncoder implements \Symfony\Component\Serializer\Encoder\EncoderInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function encode($data, string $format, array $context = [])
|
||||||
|
{
|
||||||
|
if (!$this->isAssociative($data)) {
|
||||||
|
throw new UnexpectedValueException("Only associative arrays are allowed; lists are not allowed");
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
$this->recusiveEncoding($data, $result, '');
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function recusiveEncoding(array $data, array &$result, $path)
|
||||||
|
{
|
||||||
|
if ($this->isAssociative($data)) {
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
if (\is_array($value)) {
|
||||||
|
$this->recusiveEncoding($value, $result, $this->canonicalizeKey($path, $key));
|
||||||
|
} else {
|
||||||
|
$result[$this->canonicalizeKey($path, $key)] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach ($data as $elem) {
|
||||||
|
|
||||||
|
if (!$this->isAssociative($elem)) {
|
||||||
|
throw new UnexpectedValueException(sprintf("Embedded loops are not allowed. See data under %s path", $path));
|
||||||
|
}
|
||||||
|
|
||||||
|
$sub = [];
|
||||||
|
$this->recusiveEncoding($elem, $sub, '');
|
||||||
|
$result[$path][] = $sub;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function canonicalizeKey(string $path, string $key): string
|
||||||
|
{
|
||||||
|
return $path === '' ? $key : $path.'_'.$key;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isAssociative(array $data)
|
||||||
|
{
|
||||||
|
$keys = \array_keys($data);
|
||||||
|
|
||||||
|
return $keys !== \array_keys($keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function supportsEncoding(string $format)
|
||||||
|
{
|
||||||
|
return $format === 'docgen';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\DocGeneratorBundle\Serializer\Helper;
|
||||||
|
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
|
|
||||||
|
class NormalizeNullValueHelper
|
||||||
|
{
|
||||||
|
private NormalizerInterface $normalizer;
|
||||||
|
|
||||||
|
public function __construct(NormalizerInterface $normalizer)
|
||||||
|
{
|
||||||
|
$this->normalizer = $normalizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function normalize(array $attributes, string $format = 'docgen', ?array $context = [])
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
foreach ($attributes as $key => $class) {
|
||||||
|
if (is_numeric($key)) {
|
||||||
|
$data[$class] = '';
|
||||||
|
} else {
|
||||||
|
switch ($class) {
|
||||||
|
case 'array':
|
||||||
|
case 'bool':
|
||||||
|
case 'double':
|
||||||
|
case 'float':
|
||||||
|
case 'int':
|
||||||
|
case 'resource':
|
||||||
|
case 'string':
|
||||||
|
case 'null':
|
||||||
|
$data[$key] = '';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$data[$key] = $this->normalizer->normalize(null, $format, \array_merge(
|
||||||
|
$context,
|
||||||
|
['docgen:expects' => $class]
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,177 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\DocGeneratorBundle\Serializer\Normalizer;
|
||||||
|
|
||||||
|
use Chill\DocGeneratorBundle\Serializer\Helper\NormalizeNullValueHelper;
|
||||||
|
use Symfony\Component\PropertyAccess\PropertyAccess;
|
||||||
|
use Symfony\Component\PropertyAccess\PropertyAccessor;
|
||||||
|
use Symfony\Component\Serializer\Exception\ExceptionInterface;
|
||||||
|
use Symfony\Component\Serializer\Exception\LogicException;
|
||||||
|
use Symfony\Component\Serializer\Mapping\AttributeMetadata;
|
||||||
|
use Symfony\Component\Serializer\Mapping\ClassMetadata;
|
||||||
|
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
|
|
||||||
|
class DocGenObjectNormalizer implements NormalizerInterface, NormalizerAwareInterface
|
||||||
|
{
|
||||||
|
use NormalizerAwareTrait;
|
||||||
|
|
||||||
|
private ClassMetadataFactoryInterface $classMetadataFactory;
|
||||||
|
private PropertyAccessor $propertyAccess;
|
||||||
|
|
||||||
|
public function __construct(ClassMetadataFactoryInterface $classMetadataFactory)
|
||||||
|
{
|
||||||
|
$this->classMetadataFactory = $classMetadataFactory;
|
||||||
|
$this->propertyAccess = PropertyAccess::createPropertyAccessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function normalize($object, string $format = null, array $context = [])
|
||||||
|
{
|
||||||
|
$classMetadataKey = $object ?? $context['docgen:expects'];
|
||||||
|
|
||||||
|
if (!$this->classMetadataFactory->hasMetadataFor($classMetadataKey)) {
|
||||||
|
throw new LogicException(sprintf("This object does not have metadata: %s. Add groups on this entity to allow to serialize with the format %s and groups %s", is_object($object) ? get_class($object) : $context['docgen:expects'], $format, \implode(', ', $context['groups'])));
|
||||||
|
}
|
||||||
|
|
||||||
|
$metadata = $this->classMetadataFactory->getMetadataFor($classMetadataKey);
|
||||||
|
$expectedGroups = \array_key_exists(AbstractNormalizer::GROUPS, $context) ?
|
||||||
|
\is_array($context[AbstractNormalizer::GROUPS]) ? $context[AbstractNormalizer::GROUPS] : [$context[AbstractNormalizer::GROUPS]]
|
||||||
|
: [];
|
||||||
|
$attributes = \array_filter(
|
||||||
|
$metadata->getAttributesMetadata(),
|
||||||
|
function (AttributeMetadata $a) use ($expectedGroups) {
|
||||||
|
foreach ($a->getGroups() as $g) {
|
||||||
|
if (\in_array($g, $expectedGroups, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (null === $object) {
|
||||||
|
return $this->normalizeNullData($format, $context, $metadata, $attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->normalizeObject($object, $format, $context, $expectedGroups, $metadata, $attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $format
|
||||||
|
* @param array $context
|
||||||
|
* @param array $expectedGroups
|
||||||
|
* @param ClassMetadata $metadata
|
||||||
|
* @param array|AttributeMetadata[] $attributes
|
||||||
|
*/
|
||||||
|
private function normalizeNullData(string $format, array $context, ClassMetadata $metadata, array $attributes): array
|
||||||
|
{
|
||||||
|
$keys = [];
|
||||||
|
|
||||||
|
foreach ($attributes as $attribute) {
|
||||||
|
$key = $attribute->getSerializedName() ?? $attribute->getName();
|
||||||
|
$keys[$key] = $this->getExpectedType($attribute, $metadata->getReflectionClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
$normalizer = new NormalizeNullValueHelper($this->normalizer);
|
||||||
|
|
||||||
|
return $normalizer->normalize($keys, $format, $context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $object
|
||||||
|
* @param $format
|
||||||
|
* @param array $context
|
||||||
|
* @param array $expectedGroups
|
||||||
|
* @param ClassMetadata $metadata
|
||||||
|
* @param array|AttributeMetadata[] $attributes
|
||||||
|
* @return array
|
||||||
|
* @throws ExceptionInterface
|
||||||
|
*/
|
||||||
|
private function normalizeObject($object, $format, array $context, array $expectedGroups, ClassMetadata $metadata, array $attributes)
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
$reflection = $metadata->getReflectionClass();
|
||||||
|
|
||||||
|
foreach ($attributes as $attribute) {
|
||||||
|
/** @var AttributeMetadata $attribute */
|
||||||
|
$value = $this->propertyAccess->getValue($object, $attribute->getName());
|
||||||
|
$key = $attribute->getSerializedName() ?? $attribute->getName();
|
||||||
|
|
||||||
|
if (is_object($value)) {
|
||||||
|
$data[$key] =
|
||||||
|
$this->normalizer->normalize($value, $format, \array_merge(
|
||||||
|
$context, $attribute->getNormalizationContextForGroups($expectedGroups)
|
||||||
|
));
|
||||||
|
} elseif (null === $value) {
|
||||||
|
$data[$key] = $this->normalizeNullOutputValue($format, $context, $attribute, $reflection);
|
||||||
|
} else {
|
||||||
|
$data[$key] = (string) $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getExpectedType(AttributeMetadata $attribute, \ReflectionClass $reflection): string
|
||||||
|
{
|
||||||
|
// we have to get the expected content
|
||||||
|
if ($reflection->hasProperty($attribute->getName())) {
|
||||||
|
$type = $reflection->getProperty($attribute->getName())->getType();
|
||||||
|
} elseif ($reflection->hasMethod($attribute->getName())) {
|
||||||
|
$type = $reflection->getMethod($attribute->getName())->getReturnType();
|
||||||
|
} else {
|
||||||
|
throw new \LogicException(sprintf(
|
||||||
|
"Could not determine how the content is determined for the attribute %s. Add attribute property only on property or method", $attribute->getName()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $type) {
|
||||||
|
throw new \LogicException(sprintf(
|
||||||
|
"Could not determine the type for this attribute: %s. Add a return type to the method or property declaration", $attribute->getName()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $type->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
private function normalizeNullOutputValue($format, array $context, AttributeMetadata $attribute, \ReflectionClass $reflection)
|
||||||
|
{
|
||||||
|
$type = $this->getExpectedType($attribute, $reflection);
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'array':
|
||||||
|
case 'bool':
|
||||||
|
case 'double':
|
||||||
|
case 'float':
|
||||||
|
case 'int':
|
||||||
|
case 'resource':
|
||||||
|
case 'string':
|
||||||
|
return '';
|
||||||
|
default:
|
||||||
|
return $this->normalizer->normalize(
|
||||||
|
null,
|
||||||
|
$format,
|
||||||
|
\array_merge(
|
||||||
|
$context,
|
||||||
|
['docgen:expects' => $type]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function supportsNormalization($data, string $format = null): bool
|
||||||
|
{
|
||||||
|
return $format === 'docgen' && (is_object($data) || null === $data);
|
||||||
|
}
|
||||||
|
}
|
@ -8,3 +8,10 @@ services:
|
|||||||
autowire: true
|
autowire: true
|
||||||
autoconfigure: true
|
autoconfigure: true
|
||||||
resource: '../Repository/'
|
resource: '../Repository/'
|
||||||
|
|
||||||
|
Chill\DocGeneratorBundle\Serializer\Normalizer\:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
resource: '../Serializer/Normalizer/'
|
||||||
|
tags:
|
||||||
|
- { name: 'serializer.normalizer', priority: -152 }
|
||||||
|
@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\DocGeneratorBundle\Tests\Serializer\Encoder;
|
||||||
|
|
||||||
|
use Chill\DocGeneratorBundle\Serializer\Encoder\DocGenEncoder;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||||
|
|
||||||
|
class DocGenEncoderTest extends TestCase
|
||||||
|
{
|
||||||
|
private DocGenEncoder $encoder;
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->encoder = new DocGenEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider generateEncodeData
|
||||||
|
*/
|
||||||
|
public function testEncode($expected, $data, string $msg)
|
||||||
|
{
|
||||||
|
$generated = $this->encoder->encode($data, 'docgen');
|
||||||
|
$this->assertEquals($expected, $generated, $msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEmbeddedLoopsThrowsException()
|
||||||
|
{
|
||||||
|
$this->expectException(UnexpectedValueException::class);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'data' => [
|
||||||
|
['item' => 'one'],
|
||||||
|
[
|
||||||
|
'embedded' => [
|
||||||
|
[
|
||||||
|
['subitem' => 'two'],
|
||||||
|
['subitem' => 'three']
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->encoder->encode($data, 'docgen');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateEncodeData()
|
||||||
|
{
|
||||||
|
yield [ ['tests' => 'ok'], ['tests' => 'ok'], "A simple test with a simple array"];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
// expected:
|
||||||
|
['item_subitem' => 'value'],
|
||||||
|
// data:
|
||||||
|
['item' => ['subitem' => 'value']],
|
||||||
|
"A test with multidimensional array"
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
// expected:
|
||||||
|
[ 'data' => [['item' => 'one'], ['item' => 'two']] ],
|
||||||
|
// data:
|
||||||
|
[ 'data' => [['item' => 'one'], ['item' => 'two']] ],
|
||||||
|
"a list of items"
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
// expected:
|
||||||
|
[ 'data' => [['item_subitem' => 'alpha'], ['item' => 'two']] ],
|
||||||
|
// data:
|
||||||
|
[ 'data' => [['item' => ['subitem' => 'alpha']], ['item' => 'two'] ] ],
|
||||||
|
"a list of items with multidimensional array inside item"
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
// expected:
|
||||||
|
[
|
||||||
|
'persons' => [
|
||||||
|
[
|
||||||
|
'firstname' => 'Jonathan',
|
||||||
|
'lastname' => 'Dupont',
|
||||||
|
'dateOfBirth_long' => '16 juin 1981',
|
||||||
|
'dateOfBirth_short' => '16/06/1981',
|
||||||
|
'father_firstname' => 'Marcel',
|
||||||
|
'father_lastname' => 'Dupont',
|
||||||
|
'father_dateOfBirth_long' => '10 novembre 1953',
|
||||||
|
'father_dateOfBirth_short' => '10/11/1953'
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
// data:
|
||||||
|
[
|
||||||
|
'persons' => [
|
||||||
|
[
|
||||||
|
'firstname' => 'Jonathan',
|
||||||
|
'lastname' => 'Dupont',
|
||||||
|
'dateOfBirth' => [ 'long' => '16 juin 1981', 'short' => '16/06/1981'],
|
||||||
|
'father' => [
|
||||||
|
'firstname' => 'Marcel',
|
||||||
|
'lastname' => 'Dupont',
|
||||||
|
'dateOfBirth' => ['long' => '10 novembre 1953', 'short' => '10/11/1953']
|
||||||
|
]
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"a longer list, with near real data inside and embedded associative arrays"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\DocGeneratorBundle\tests\Serializer\Normalizer;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\Center;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
|
|
||||||
|
class DocGenObjectNormalizerTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
private NormalizerInterface $normalizer;
|
||||||
|
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
self::bootKernel();
|
||||||
|
|
||||||
|
$this->normalizer = self::$container->get(NormalizerInterface::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNormalizationBasic()
|
||||||
|
{
|
||||||
|
$user = new User();
|
||||||
|
$user->setUsername('User Test');
|
||||||
|
$user->setMainCenter($center = new Center());
|
||||||
|
$center->setName('test');
|
||||||
|
|
||||||
|
$normalized = $this->normalizer->normalize($user, 'docgen', [ AbstractNormalizer::GROUPS => ['docgen:read']]);
|
||||||
|
$expected = [
|
||||||
|
'label' => 'User Test',
|
||||||
|
'email' => '',
|
||||||
|
'mainCenter' => [
|
||||||
|
'name' => 'test'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $normalized, "test normalization fo an user");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNormalizeWithNullValueEmbedded()
|
||||||
|
{
|
||||||
|
$user = new User();
|
||||||
|
$user->setUsername('User Test');
|
||||||
|
|
||||||
|
$normalized = $this->normalizer->normalize($user, 'docgen', [ AbstractNormalizer::GROUPS => ['docgen:read']]);
|
||||||
|
$expected = [
|
||||||
|
'label' => 'User Test',
|
||||||
|
'email' => '',
|
||||||
|
'mainCenter' => [
|
||||||
|
'name' => ''
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $normalized, "test normalization fo an user with null center");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNormalizeNullObjectWithObjectEmbedded()
|
||||||
|
{
|
||||||
|
$normalized = $this->normalizer->normalize(null, 'docgen', [
|
||||||
|
AbstractNormalizer::GROUPS => ['docgen:read'],
|
||||||
|
'docgen:expects' => User::class,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
'label' => '',
|
||||||
|
'email' => '',
|
||||||
|
'mainCenter' => [
|
||||||
|
'name' => ''
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expected, $normalized, "test normalization for a null user");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,19 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
* Copyright (C) 2014, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* it under the terms of the GNU Affero General Public License as
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
* License, or (at your option) any later version.
|
* License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Affero General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
@ -23,12 +23,11 @@ namespace Chill\MainBundle\Entity;
|
|||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Entity
|
* @ORM\Entity
|
||||||
* @ORM\Table(name="centers")
|
* @ORM\Table(name="centers")
|
||||||
*
|
|
||||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
|
||||||
*/
|
*/
|
||||||
class Center implements HasCenterInterface
|
class Center implements HasCenterInterface
|
||||||
{
|
{
|
||||||
@ -46,9 +45,10 @@ class Center implements HasCenterInterface
|
|||||||
* @var string
|
* @var string
|
||||||
*
|
*
|
||||||
* @ORM\Column(type="string", length=255)
|
* @ORM\Column(type="string", length=255)
|
||||||
|
* @Serializer\Groups({"docgen:read"})
|
||||||
*/
|
*/
|
||||||
private $name;
|
private string $name = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Collection
|
* @var Collection
|
||||||
*
|
*
|
||||||
@ -58,8 +58,8 @@ class Center implements HasCenterInterface
|
|||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
private $groupCenters;
|
private $groupCenters;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Center constructor.
|
* Center constructor.
|
||||||
*/
|
*/
|
||||||
@ -67,7 +67,7 @@ class Center implements HasCenterInterface
|
|||||||
{
|
{
|
||||||
$this->groupCenters = new \Doctrine\Common\Collections\ArrayCollection();
|
$this->groupCenters = new \Doctrine\Common\Collections\ArrayCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -75,7 +75,7 @@ class Center implements HasCenterInterface
|
|||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $name
|
* @param $name
|
||||||
* @return $this
|
* @return $this
|
||||||
@ -85,7 +85,7 @@ class Center implements HasCenterInterface
|
|||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
@ -93,7 +93,7 @@ class Center implements HasCenterInterface
|
|||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return ArrayCollection|Collection
|
* @return ArrayCollection|Collection
|
||||||
*/
|
*/
|
||||||
@ -101,7 +101,7 @@ class Center implements HasCenterInterface
|
|||||||
{
|
{
|
||||||
return $this->groupCenters;
|
return $this->groupCenters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param GroupCenter $groupCenter
|
* @param GroupCenter $groupCenter
|
||||||
* @return $this
|
* @return $this
|
||||||
@ -111,7 +111,7 @@ class Center implements HasCenterInterface
|
|||||||
$this->groupCenters->add($groupCenter);
|
$this->groupCenters->add($groupCenter);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
@ -119,7 +119,7 @@ class Center implements HasCenterInterface
|
|||||||
{
|
{
|
||||||
return $this->getName();
|
return $this->getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return $this|Center
|
* @return $this|Center
|
||||||
*/
|
*/
|
||||||
|
@ -8,7 +8,7 @@ use Doctrine\Common\Collections\ArrayCollection;
|
|||||||
use Chill\MainBundle\Entity\UserJob;
|
use Chill\MainBundle\Entity\UserJob;
|
||||||
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
|
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
|
||||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User
|
* User
|
||||||
@ -16,7 +16,7 @@ use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
|||||||
* @ORM\Entity
|
* @ORM\Entity
|
||||||
* @ORM\Table(name="users")
|
* @ORM\Table(name="users")
|
||||||
* @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region")
|
* @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="acl_cache_region")
|
||||||
* @DiscriminatorMap(typeProperty="type", mapping={
|
* @Serializer\DiscriminatorMap(typeProperty="type", mapping={
|
||||||
* "user"=User::class
|
* "user"=User::class
|
||||||
* })
|
* })
|
||||||
*/
|
*/
|
||||||
@ -51,6 +51,7 @@ class User implements AdvancedUserInterface {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", length=200)
|
* @ORM\Column(type="string", length=200)
|
||||||
|
* @Serializer\Groups({"docgen:read"})
|
||||||
*/
|
*/
|
||||||
private string $label = '';
|
private string $label = '';
|
||||||
|
|
||||||
@ -58,8 +59,9 @@ class User implements AdvancedUserInterface {
|
|||||||
* @var string
|
* @var string
|
||||||
*
|
*
|
||||||
* @ORM\Column(type="string", length=150, nullable=true)
|
* @ORM\Column(type="string", length=150, nullable=true)
|
||||||
|
* @Serializer\Groups({"docgen:read"})
|
||||||
*/
|
*/
|
||||||
private $email;
|
private ?string $email = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
@ -123,6 +125,7 @@ class User implements AdvancedUserInterface {
|
|||||||
/**
|
/**
|
||||||
* @var Center|null
|
* @var Center|null
|
||||||
* @ORM\ManyToOne(targetEntity=Center::class)
|
* @ORM\ManyToOne(targetEntity=Center::class)
|
||||||
|
* @Serializer\Groups({"docgen:read"})
|
||||||
*/
|
*/
|
||||||
private ?Center $mainCenter = null;
|
private ?Center $mainCenter = null;
|
||||||
|
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
* Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS, <http://www.champs-libres.coop>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* it under the terms of the GNU Affero General Public License as
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
* License, or (at your option) any later version.
|
* License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Affero General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
@ -27,7 +27,7 @@ use Symfony\Component\Serializer\Exception\InvalidArgumentException;
|
|||||||
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class CenterNormalizer implements NormalizerInterface, DenormalizerInterface
|
class CenterNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||||
@ -52,7 +52,7 @@ class CenterNormalizer implements NormalizerInterface, DenormalizerInterface
|
|||||||
|
|
||||||
public function supportsNormalization($data, string $format = null): bool
|
public function supportsNormalization($data, string $format = null): bool
|
||||||
{
|
{
|
||||||
return $data instanceof Center;
|
return $data instanceof Center && $format === 'json';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function denormalize($data, string $type, string $format = null, array $context = [])
|
public function denormalize($data, string $type, string $format = null, array $context = [])
|
||||||
|
@ -19,23 +19,78 @@
|
|||||||
|
|
||||||
namespace Chill\MainBundle\Serializer\Normalizer;
|
namespace Chill\MainBundle\Serializer\Normalizer;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
|
|
||||||
class DateNormalizer implements NormalizerInterface, DenormalizerInterface
|
class DateNormalizer implements ContextAwareNormalizerInterface, DenormalizerInterface
|
||||||
{
|
{
|
||||||
|
private RequestStack $requestStack;
|
||||||
|
private ParameterBagInterface $parameterBag;
|
||||||
|
|
||||||
|
public function __construct(RequestStack $requestStack, ParameterBagInterface $parameterBag)
|
||||||
|
{
|
||||||
|
$this->requestStack = $requestStack;
|
||||||
|
$this->parameterBag = $parameterBag;
|
||||||
|
}
|
||||||
|
|
||||||
public function normalize($date, string $format = null, array $context = array())
|
public function normalize($date, string $format = null, array $context = array())
|
||||||
{
|
{
|
||||||
/** @var \DateTimeInterface $date */
|
/** @var \DateTimeInterface $date */
|
||||||
return [
|
switch($format) {
|
||||||
'datetime' => $date->format(\DateTimeInterface::ISO8601)
|
case 'json':
|
||||||
];
|
return [
|
||||||
|
'datetime' => $date->format(\DateTimeInterface::ISO8601)
|
||||||
|
];
|
||||||
|
case 'docgen':
|
||||||
|
|
||||||
|
if (null === $date) {
|
||||||
|
return [
|
||||||
|
'long' => '', 'short' => ''
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$hasTime = $date->format('His') !== "000000";
|
||||||
|
$request = $this->requestStack->getCurrentRequest();
|
||||||
|
$locale = null !== $request ? $request->getLocale() : $this->parameterBag->get('kernel.default_locale');
|
||||||
|
$formatterLong = \IntlDateFormatter::create(
|
||||||
|
$locale,
|
||||||
|
\IntlDateFormatter::LONG,
|
||||||
|
$hasTime ? \IntlDateFormatter::SHORT: \IntlDateFormatter::NONE
|
||||||
|
);
|
||||||
|
$formatterShort = \IntlDateFormatter::create(
|
||||||
|
$locale,
|
||||||
|
\IntlDateFormatter::SHORT,
|
||||||
|
$hasTime ? \IntlDateFormatter::SHORT: \IntlDateFormatter::NONE
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'short' => $formatterShort->format($date),
|
||||||
|
'long' => $formatterLong->format($date)
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function supportsNormalization($data, string $format = null): bool
|
public function supportsNormalization($data, string $format = null, array $context = []): bool
|
||||||
{
|
{
|
||||||
return $data instanceof \DateTimeInterface;
|
if ($format === 'json') {
|
||||||
|
return $data instanceof \DateTimeInterface;
|
||||||
|
} elseif ($format === 'docgen') {
|
||||||
|
return $data instanceof \DateTimeInterface || (
|
||||||
|
$data === null
|
||||||
|
&& \array_key_exists('docgen:expects', $context)
|
||||||
|
&& (
|
||||||
|
$context['docgen:expects'] === \DateTimeInterface::class
|
||||||
|
|| $context['docgen:expects'] === \DateTime::class
|
||||||
|
|| $context['docgen:expects'] === \DateTimeImmutable::class
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function denormalize($data, string $type, string $format = null, array $context = [])
|
public function denormalize($data, string $type, string $format = null, array $context = [])
|
||||||
|
@ -52,6 +52,6 @@ class UserNormalizer implements NormalizerInterface, NormalizerAwareInterface
|
|||||||
|
|
||||||
public function supportsNormalization($data, string $format = null): bool
|
public function supportsNormalization($data, string $format = null): bool
|
||||||
{
|
{
|
||||||
return $data instanceof User;
|
return $format === 'json' && $data instanceof User;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Serializer\Normalizer;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Serializer\Normalizer\DateNormalizer;
|
||||||
|
use Prophecy\Prophet;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
|
||||||
|
class DateNormalizerTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
private Prophet $prophet;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
$this->prophet = new Prophet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSupports()
|
||||||
|
{
|
||||||
|
$this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTime(), 'json'));
|
||||||
|
$this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTimeImmutable(), 'json'));
|
||||||
|
$this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTime(), 'docgen'));
|
||||||
|
$this->assertTrue($this->buildDateNormalizer()->supportsNormalization(new \DateTimeImmutable(), 'docgen'));
|
||||||
|
$this->assertTrue($this->buildDateNormalizer()->supportsNormalization(null, 'docgen', ['docgen:expects' => \DateTimeImmutable::class]));
|
||||||
|
$this->assertTrue($this->buildDateNormalizer()->supportsNormalization(null, 'docgen', ['docgen:expects' => \DateTimeInterface::class]));
|
||||||
|
$this->assertTrue($this->buildDateNormalizer()->supportsNormalization(null, 'docgen', ['docgen:expects' => \DateTime::class]));
|
||||||
|
$this->assertFalse($this->buildDateNormalizer()->supportsNormalization(new \stdClass(), 'docgen'));
|
||||||
|
$this->assertFalse($this->buildDateNormalizer()->supportsNormalization(new \DateTime(), 'xml'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider generateDataNormalize
|
||||||
|
*/
|
||||||
|
public function testNormalize($expected, $date, $format, $locale, $msg)
|
||||||
|
{
|
||||||
|
$this->assertEquals($expected, $this->buildDateNormalizer($locale)->normalize($date, $format, []), $msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildDateNormalizer(string $locale = null): DateNormalizer
|
||||||
|
{
|
||||||
|
$requestStack = $this->prophet->prophesize(RequestStack::class);
|
||||||
|
$parameterBag = new ParameterBag();
|
||||||
|
$parameterBag->set('kernel.default_locale', 'fr');
|
||||||
|
|
||||||
|
if ($locale === null) {
|
||||||
|
$requestStack->getCurrentRequest()->willReturn(null);
|
||||||
|
} else {
|
||||||
|
$request = $this->prophet->prophesize(Request::class);
|
||||||
|
$request->getLocale()->willReturn($locale);
|
||||||
|
$requestStack->getCurrentRequest()->willReturn($request->reveal());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DateNormalizer($requestStack->reveal(), $parameterBag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateDataNormalize()
|
||||||
|
{
|
||||||
|
$datetime = \DateTime::createFromFormat('Y-m-d H:i:sO', '2021-06-05 15:05:01+02:00');
|
||||||
|
$date = \DateTime::createFromFormat('Y-m-d H:i:sO', '2021-06-05 00:00:00+02:00');
|
||||||
|
yield [
|
||||||
|
['datetime' => '2021-06-05T15:05:01+0200'],
|
||||||
|
$datetime, 'json', null, 'simple normalization to json'
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
['long' => '5 juin 2021', 'short' => '05/06/2021'],
|
||||||
|
$date, 'docgen', 'fr', 'normalization to docgen for a date, with current request'
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
['long' => '5 juin 2021', 'short' => '05/06/2021'],
|
||||||
|
$date, 'docgen', null, 'normalization to docgen for a date, without current request'
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
['long' => '5 juin 2021 à 15:05', 'short' => '05/06/2021 15:05'],
|
||||||
|
$datetime, 'docgen', null, 'normalization to docgen for a datetime, without current request'
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
['long' => '', 'short' => ''],
|
||||||
|
null, 'docgen', null, 'normalization to docgen for a null datetime'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -1139,11 +1139,11 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
|
|
||||||
public function getGroupSequence()
|
public function getGroupSequence()
|
||||||
{
|
{
|
||||||
if ($this->getStep() == self::STEP_DRAFT) {
|
if ($this->getStep() == self::STEP_DRAFT)
|
||||||
|
{
|
||||||
return [[self::STEP_DRAFT]];
|
return [[self::STEP_DRAFT]];
|
||||||
}
|
} elseif ($this->getStep() == self::STEP_CONFIRMED)
|
||||||
|
{
|
||||||
if ($this->getStep() == self::STEP_CONFIRMED) {
|
|
||||||
return [[self::STEP_DRAFT, self::STEP_CONFIRMED]];
|
return [[self::STEP_DRAFT, self::STEP_CONFIRMED]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,20 +37,20 @@ class MaritalStatus
|
|||||||
* @ORM\Id()
|
* @ORM\Id()
|
||||||
* @ORM\Column(type="string", length=7)
|
* @ORM\Column(type="string", length=7)
|
||||||
*/
|
*/
|
||||||
private $id;
|
private ?string $id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string array
|
* @var string array
|
||||||
* @ORM\Column(type="json")
|
* @ORM\Column(type="json")
|
||||||
*/
|
*/
|
||||||
private $name;
|
private array $name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get id
|
* Get id
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getId()
|
public function getId(): string
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
@ -61,7 +61,7 @@ class MaritalStatus
|
|||||||
* @param string $id
|
* @param string $id
|
||||||
* @return MaritalStatus
|
* @return MaritalStatus
|
||||||
*/
|
*/
|
||||||
public function setId($id)
|
public function setId(string $id): self
|
||||||
{
|
{
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
return $this;
|
return $this;
|
||||||
@ -73,7 +73,7 @@ class MaritalStatus
|
|||||||
* @param string array $name
|
* @param string array $name
|
||||||
* @return MaritalStatus
|
* @return MaritalStatus
|
||||||
*/
|
*/
|
||||||
public function setName($name)
|
public function setName(array $name): self
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ class MaritalStatus
|
|||||||
*
|
*
|
||||||
* @return string array
|
* @return string array
|
||||||
*/
|
*/
|
||||||
public function getName()
|
public function getName(): array
|
||||||
{
|
{
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
@ -219,7 +219,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
* groups={"general", "creation"}
|
* groups={"general", "creation"}
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
private ?\DateTime $maritalStatusDate;
|
private ?\DateTime $maritalStatusDate = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comment on marital status
|
* Comment on marital status
|
||||||
@ -252,7 +252,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
* The person's phonenumber
|
* The person's phonenumber
|
||||||
* @var string
|
* @var string
|
||||||
*
|
*
|
||||||
* @ORM\Column(type="text", length=40, nullable=true)
|
* @ORM\Column(type="text")
|
||||||
* @Assert\Regex(
|
* @Assert\Regex(
|
||||||
* pattern="/^([\+{1}])([0-9\s*]{4,20})$/",
|
* pattern="/^([\+{1}])([0-9\s*]{4,20})$/",
|
||||||
* groups={"general", "creation"}
|
* groups={"general", "creation"}
|
||||||
@ -262,13 +262,13 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
* groups={"general", "creation"}
|
* groups={"general", "creation"}
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
private $phonenumber = '';
|
private string $phonenumber = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The person's mobile phone number
|
* The person's mobile phone number
|
||||||
* @var string
|
* @var string
|
||||||
*
|
*
|
||||||
* @ORM\Column(type="text", length=40, nullable=true)
|
* @ORM\Column(type="text")
|
||||||
* @Assert\Regex(
|
* @Assert\Regex(
|
||||||
* pattern="/^([\+{1}])([0-9\s*]{4,20})$/",
|
* pattern="/^([\+{1}])([0-9\s*]{4,20})$/",
|
||||||
* groups={"general", "creation"}
|
* groups={"general", "creation"}
|
||||||
@ -278,7 +278,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
* groups={"general", "creation"}
|
* groups={"general", "creation"}
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
private $mobilenumber = '';
|
private string $mobilenumber = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Collection
|
* @var Collection
|
||||||
@ -1094,9 +1094,9 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
/**
|
/**
|
||||||
* Get nationality
|
* Get nationality
|
||||||
*
|
*
|
||||||
* @return Chill\MainBundle\Entity\Country
|
* @return Country
|
||||||
*/
|
*/
|
||||||
public function getNationality()
|
public function getNationality(): ?Country
|
||||||
{
|
{
|
||||||
return $this->nationality;
|
return $this->nationality;
|
||||||
}
|
}
|
||||||
@ -1176,7 +1176,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getPhonenumber()
|
public function getPhonenumber(): string
|
||||||
{
|
{
|
||||||
return $this->phonenumber;
|
return $this->phonenumber;
|
||||||
}
|
}
|
||||||
@ -1199,7 +1199,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getMobilenumber()
|
public function getMobilenumber(): string
|
||||||
{
|
{
|
||||||
return $this->mobilenumber;
|
return $this->mobilenumber;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -39,7 +39,7 @@ use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;
|
|||||||
* Serialize a Person entity
|
* Serialize a Person entity
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class PersonNormalizer implements
|
class PersonJsonNormalizer implements
|
||||||
NormalizerInterface,
|
NormalizerInterface,
|
||||||
NormalizerAwareInterface,
|
NormalizerAwareInterface,
|
||||||
DenormalizerInterface,
|
DenormalizerInterface,
|
||||||
@ -105,7 +105,7 @@ class PersonNormalizer implements
|
|||||||
|
|
||||||
public function supportsNormalization($data, string $format = null): bool
|
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 = [])
|
public function denormalize($data, string $type, string $format = null, array $context = [])
|
||||||
@ -128,45 +128,48 @@ class PersonNormalizer implements
|
|||||||
$person = new Person();
|
$person = new Person();
|
||||||
}
|
}
|
||||||
|
|
||||||
$properties = ['firstName', 'lastName', 'phonenumber', 'mobilenumber', 'gender'];
|
foreach (['firstName', 'lastName', 'phonenumber', 'mobilenumber', 'gender',
|
||||||
|
'birthdate', 'deathdate', 'center']
|
||||||
|
as $item) {
|
||||||
|
|
||||||
$properties = array_filter(
|
if (!\array_key_exists($item, $data)) {
|
||||||
$properties,
|
continue;
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$propertyToClassMapping = [
|
switch ($item) {
|
||||||
'birthdate' => \DateTime::class,
|
case 'firstName':
|
||||||
'deathdate' => \DateTime::class,
|
$person->setFirstName($data[$item]);
|
||||||
'center' => Center::class,
|
break;
|
||||||
];
|
case 'lastName':
|
||||||
|
$person->setLastName($data[$item]);
|
||||||
$propertyToClassMapping = array_filter(
|
break;
|
||||||
$propertyToClassMapping,
|
case 'phonenumber':
|
||||||
static fn (string $item): bool => array_key_exists($item, $data)
|
$person->setPhonenumber($data[$item]);
|
||||||
);
|
break;
|
||||||
|
case 'mobilenumber':
|
||||||
foreach ($propertyToClassMapping as $item => $class) {
|
$person->setMobilenumber($data[$item]);
|
||||||
$object = $this->denormalizer->denormalize($data[$item], $class, $format, $context);
|
break;
|
||||||
|
case 'gender':
|
||||||
if ($object instanceof $class) {
|
$person->setGender($data[$item]);
|
||||||
$callable = [$object, sprintf('set%s', ucfirst($item))];
|
break;
|
||||||
|
case 'birthdate':
|
||||||
if (is_callable($callable)) {
|
$object = $this->denormalizer->denormalize($data[$item], \DateTime::class, $format, $context);
|
||||||
$closure = \Closure::fromCallable($callable);
|
if ($object instanceof \DateTime) {
|
||||||
|
$person->setBirthdate($object);
|
||||||
$closure($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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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' => ''
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ services:
|
|||||||
|
|
||||||
Chill\PersonBundle\Serializer\Normalizer\:
|
Chill\PersonBundle\Serializer\Normalizer\:
|
||||||
autowire: true
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
resource: '../../Serializer/Normalizer'
|
resource: '../../Serializer/Normalizer'
|
||||||
tags:
|
tags:
|
||||||
- { name: 'serializer.normalizer', priority: 64 }
|
- { name: 'serializer.normalizer', priority: 64 }
|
||||||
|
@ -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');
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user