Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5352984

Browse files
committed
Merge branch '6.4' into 7.3
* 6.4: fix test setup [Validator] Review Turkish translations [Validator] Review Croatian translations [Validator] Review translations for Polish (pl) use the empty string instead of null as an array offset Review translations for Chinese (zh_TW) [Serializer] Adjust ObjectNormalizerTest for the accessor method changes from #61097
2 parents ab23820 + 672cf20 commit 5352984

2 files changed

Lines changed: 192 additions & 20 deletions

File tree

Serializer.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,8 @@ private function getNormalizer(mixed $data, ?string $format, array $context): ?N
272272
$genericType = '*';
273273
}
274274

275-
if (!isset($this->normalizerCache[$format][$type])) {
276-
$this->normalizerCache[$format][$type] = [];
275+
if (!isset($this->normalizerCache[$format ?? ''][$type])) {
276+
$this->normalizerCache[$format ?? ''][$type] = [];
277277

278278
foreach ($this->normalizers as $k => $normalizer) {
279279
if (!$normalizer instanceof NormalizerInterface) {
@@ -291,7 +291,7 @@ private function getNormalizer(mixed $data, ?string $format, array $context): ?N
291291

292292
if (null === $isCacheable) {
293293
unset($supportedTypes['*'], $supportedTypes['object']);
294-
} elseif ($this->normalizerCache[$format][$type][$k] = $isCacheable && $normalizer->supportsNormalization($data, $format, $context)) {
294+
} elseif ($this->normalizerCache[$format ?? ''][$type][$k] = $isCacheable && $normalizer->supportsNormalization($data, $format, $context)) {
295295
break 2;
296296
}
297297

@@ -302,13 +302,13 @@ private function getNormalizer(mixed $data, ?string $format, array $context): ?N
302302
continue;
303303
}
304304

305-
if ($this->normalizerCache[$format][$type][$k] ??= $isCacheable && $normalizer->supportsNormalization($data, $format, $context)) {
305+
if ($this->normalizerCache[$format ?? ''][$type][$k] ??= $isCacheable && $normalizer->supportsNormalization($data, $format, $context)) {
306306
break;
307307
}
308308
}
309309
}
310310

311-
foreach ($this->normalizerCache[$format][$type] as $k => $cached) {
311+
foreach ($this->normalizerCache[$format ?? ''][$type] as $k => $cached) {
312312
$normalizer = $this->normalizers[$k];
313313
if ($cached || $normalizer->supportsNormalization($data, $format, $context)) {
314314
return $normalizer;
@@ -328,8 +328,8 @@ private function getNormalizer(mixed $data, ?string $format, array $context): ?N
328328
*/
329329
private function getDenormalizer(mixed $data, string $class, ?string $format, array $context): ?DenormalizerInterface
330330
{
331-
if (!isset($this->denormalizerCache[$format][$class])) {
332-
$this->denormalizerCache[$format][$class] = [];
331+
if (!isset($this->denormalizerCache[$format ?? ''][$class])) {
332+
$this->denormalizerCache[$format ?? ''][$class] = [];
333333
$genericType = class_exists($class) || interface_exists($class, false) ? 'object' : '*';
334334

335335
foreach ($this->normalizers as $k => $normalizer) {
@@ -351,7 +351,7 @@ private function getDenormalizer(mixed $data, string $class, ?string $format, ar
351351

352352
if (null === $isCacheable) {
353353
unset($supportedTypes['*'], $supportedTypes['object']);
354-
} elseif ($this->denormalizerCache[$format][$class][$k] = $isCacheable && $normalizer->supportsDenormalization(null, $class, $format, $context)) {
354+
} elseif ($this->denormalizerCache[$format ?? ''][$class][$k] = $isCacheable && $normalizer->supportsDenormalization(null, $class, $format, $context)) {
355355
break 2;
356356
}
357357

@@ -362,13 +362,13 @@ private function getDenormalizer(mixed $data, string $class, ?string $format, ar
362362
continue;
363363
}
364364

365-
if ($this->denormalizerCache[$format][$class][$k] ??= $isCacheable && $normalizer->supportsDenormalization(null, $class, $format, $context)) {
365+
if ($this->denormalizerCache[$format ?? ''][$class][$k] ??= $isCacheable && $normalizer->supportsDenormalization(null, $class, $format, $context)) {
366366
break;
367367
}
368368
}
369369
}
370370

371-
foreach ($this->denormalizerCache[$format][$class] as $k => $cached) {
371+
foreach ($this->denormalizerCache[$format ?? ''][$class] as $k => $cached) {
372372
$normalizer = $this->normalizers[$k];
373373
if ($cached || $normalizer->supportsDenormalization($data, $class, $format, $context)) {
374374
return $normalizer;

Tests/Normalizer/ObjectNormalizerTest.php

Lines changed: 182 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use PHPUnit\Framework\MockObject\MockObject;
1616
use PHPUnit\Framework\TestCase;
1717
use Symfony\Component\PropertyAccess\Exception\InvalidTypeException;
18+
use Symfony\Component\PropertyAccess\PropertyAccessorBuilder;
1819
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
1920
use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor;
2021
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
@@ -963,10 +964,26 @@ public function testObjectNormalizerWithAttributeLoaderAndObjectHasStaticPropert
963964
$this->assertSame([], $normalizer->normalize($class));
964965
}
965966

966-
public function testNormalizeWithMethodNamesSimilarToAccessors()
967+
// accessors
968+
969+
protected function getNormalizerForAccessors($accessorPrefixes = null): ObjectNormalizer
967970
{
971+
$accessorPrefixes = $accessorPrefixes ?? ReflectionExtractor::$defaultAccessorPrefixes;
968972
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
969-
$normalizer = new ObjectNormalizer($classMetadataFactory);
973+
$propertyAccessorBuilder = (new PropertyAccessorBuilder())
974+
->setReadInfoExtractor(
975+
new ReflectionExtractor([], $accessorPrefixes, null, false)
976+
);
977+
978+
return new ObjectNormalizer(
979+
$classMetadataFactory,
980+
propertyAccessor: $propertyAccessorBuilder->getPropertyAccessor(),
981+
);
982+
}
983+
984+
public function testNormalizeWithMethodNamesSimilarToAccessors()
985+
{
986+
$normalizer = $this->getNormalizerForAccessors();
970987

971988
$object = new ObjectWithAccessorishMethods();
972989
$normalized = $normalizer->normalize($object);
@@ -981,19 +998,94 @@ public function testNormalizeWithMethodNamesSimilarToAccessors()
981998
], $normalized);
982999
}
9831000

984-
public function testNormalizeObjectWithBooleanPropertyAndIsserMethodWithSameName()
1001+
public function testNormalizeObjectWithPublicPropertyAccessorPrecedence()
9851002
{
986-
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
987-
$normalizer = new ObjectNormalizer($classMetadataFactory);
1003+
$normalizer = $this->getNormalizerForAccessors();
9881004

989-
$object = new ObjectWithBooleanPropertyAndIsserWithSameName();
1005+
$object = new ObjectWithPropertyAndAllAccessorMethods(
1006+
'foo',
1007+
);
9901008
$normalized = $normalizer->normalize($object);
9911009

1010+
// The getter method should take precedence over all other accessor methods
9921011
$this->assertSame([
9931012
'foo' => 'foo',
994-
'isFoo' => true,
9951013
], $normalized);
9961014
}
1015+
1016+
public function testNormalizeObjectWithPropertyAndAccessorMethodsWithSameName()
1017+
{
1018+
$normalizer = $this->getNormalizerForAccessors();
1019+
1020+
$object = new ObjectWithPropertyAndAccessorSameName(
1021+
'foo',
1022+
'getFoo',
1023+
'canFoo',
1024+
'hasFoo',
1025+
'isFoo'
1026+
);
1027+
$normalized = $normalizer->normalize($object);
1028+
1029+
// Accessor methods with exactly the same name as the property should take precedence
1030+
$this->assertSame([
1031+
'getFoo' => 'getFoo',
1032+
'canFoo' => 'canFoo',
1033+
'hasFoo' => 'hasFoo',
1034+
'isFoo' => 'isFoo',
1035+
// The getFoo accessor method is used for foo, thus it's also 'getFoo' instead of 'foo'
1036+
'foo' => 'getFoo',
1037+
], $normalized);
1038+
1039+
$denormalized = $this->normalizer->denormalize($normalized, ObjectWithPropertyAndAccessorSameName::class);
1040+
1041+
$this->assertSame('getFoo', $denormalized->getFoo());
1042+
1043+
// On the initial object the value was 'foo', but the normalizer prefers the accessor method 'getFoo'
1044+
// Thus on the denoramilzed object the value is 'getFoo'
1045+
$this->assertSame('foo', $object->foo);
1046+
$this->assertSame('getFoo', $denormalized->foo);
1047+
1048+
$this->assertSame('hasFoo', $denormalized->hasFoo());
1049+
$this->assertSame('canFoo', $denormalized->canFoo());
1050+
$this->assertSame('isFoo', $denormalized->isFoo());
1051+
}
1052+
1053+
/**
1054+
* Priority of accessor methods is defined by the PropertyReadInfoExtractorInterface passed to the PropertyAccessor
1055+
* component. By default ReflectionExtractor::$defaultAccessorPrefixes are used.
1056+
*/
1057+
public function testPrecedenceOfAccessorMethods()
1058+
{
1059+
// by default 'is' comes before 'has'
1060+
$defaultAccessorPrefixNormalizer = $this->getNormalizerForAccessors();
1061+
$swappedAccessorPrefixNormalizer = $this->getNormalizerForAccessors(['has', 'is']);
1062+
1063+
// Nearly equal class, only accessor order is different
1064+
$isserHasserObject = new ObjectWithPropertyIsserAndHasser('foo');
1065+
$hasserIsserObject = new ObjectWithPropertyHasserAndIsser('foo');
1066+
1067+
// default precedence (is, has)
1068+
$normalizedDefaultIsserHasser = $defaultAccessorPrefixNormalizer->normalize($isserHasserObject);
1069+
$normalizedDefaultHasserIsser = $defaultAccessorPrefixNormalizer->normalize($hasserIsserObject);
1070+
1071+
$this->assertSame([
1072+
'foo' => 'isFoo',
1073+
], $normalizedDefaultIsserHasser);
1074+
$this->assertSame([
1075+
'foo' => 'isFoo',
1076+
], $normalizedDefaultHasserIsser);
1077+
1078+
// swapped precedence (has, is)
1079+
$normalizedSwappedIsserHasser = $swappedAccessorPrefixNormalizer->normalize($isserHasserObject);
1080+
$normalizedSwappedHasserIsser = $swappedAccessorPrefixNormalizer->normalize($hasserIsserObject);
1081+
1082+
$this->assertSame([
1083+
'foo' => 'hasFoo',
1084+
], $normalizedSwappedIsserHasser);
1085+
$this->assertSame([
1086+
'foo' => 'hasFoo',
1087+
], $normalizedSwappedHasserIsser);
1088+
}
9971089
}
9981090

9991091
class ProxyObjectDummy extends ObjectDummy
@@ -1337,18 +1429,98 @@ public function isolate()
13371429
}
13381430
}
13391431

1340-
class ObjectWithBooleanPropertyAndIsserWithSameName
1432+
class ObjectWithPropertyAndAllAccessorMethods
13411433
{
1342-
private $foo = 'foo';
1343-
private $isFoo = true;
1434+
public function __construct(
1435+
private $foo,
1436+
) {
1437+
}
1438+
1439+
public function canFoo()
1440+
{
1441+
return 'canFoo';
1442+
}
13441443

13451444
public function getFoo()
13461445
{
13471446
return $this->foo;
13481447
}
13491448

1449+
public function hasFoo()
1450+
{
1451+
return 'hasFoo';
1452+
}
1453+
1454+
public function isFoo()
1455+
{
1456+
return 'isFoo';
1457+
}
1458+
}
1459+
1460+
class ObjectWithPropertyAndAccessorSameName
1461+
{
1462+
public function __construct(
1463+
public $foo,
1464+
private $getFoo,
1465+
private $canFoo = null,
1466+
private $hasFoo = null,
1467+
private $isFoo = null,
1468+
) {
1469+
}
1470+
1471+
public function getFoo()
1472+
{
1473+
return $this->getFoo;
1474+
}
1475+
1476+
public function canFoo()
1477+
{
1478+
return $this->canFoo;
1479+
}
1480+
1481+
public function hasFoo()
1482+
{
1483+
return $this->hasFoo;
1484+
}
1485+
13501486
public function isFoo()
13511487
{
13521488
return $this->isFoo;
13531489
}
13541490
}
1491+
1492+
class ObjectWithPropertyHasserAndIsser
1493+
{
1494+
public function __construct(
1495+
private $foo,
1496+
) {
1497+
}
1498+
1499+
public function hasFoo()
1500+
{
1501+
return 'hasFoo';
1502+
}
1503+
1504+
public function isFoo()
1505+
{
1506+
return 'isFoo';
1507+
}
1508+
}
1509+
1510+
class ObjectWithPropertyIsserAndHasser
1511+
{
1512+
public function __construct(
1513+
private $foo,
1514+
) {
1515+
}
1516+
1517+
public function isFoo()
1518+
{
1519+
return 'isFoo';
1520+
}
1521+
1522+
public function hasFoo()
1523+
{
1524+
return 'hasFoo';
1525+
}
1526+
}

0 commit comments

Comments
 (0)