Skip to content

Commit 2151958

Browse files
committed
match denormalized properties, fixes #565
1 parent e0221a3 commit 2151958

2 files changed

Lines changed: 74 additions & 2 deletions

File tree

src/Serializer/Denormalizer.php

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,8 @@ private function findPropertySetter(MapCell $mapCell, ReflectionMethod|Reflectio
341341
}
342342

343343
/** @var int<0, max>|false $index */
344-
$index = array_search($offset, $propertyNames, true);
344+
$index = self::normalizedMatch($offset, $propertyNames);
345+
345346
if (false === $index) {
346347
throw new MappingFailed('The `'.$offset.'` property could not be found in the property names list; Please verify your property names list.');
347348
}
@@ -370,7 +371,34 @@ private function findPropertySetter(MapCell $mapCell, ReflectionMethod|Reflectio
370371
};
371372
}
372373

373-
/**
374+
375+
376+
public static function normalizedMatch(string $needle, array $haystack): int|false
377+
{
378+
$normalizedNeedle = self::normalizeKey($needle);
379+
380+
foreach ($haystack as $index => $item) {
381+
if (self::normalizeKey($item) === $normalizedNeedle) {
382+
return $index; // Return the matching index
383+
}
384+
}
385+
386+
return false; // No match
387+
}
388+
389+
private static function normalizeKey(string $key): string
390+
{
391+
// Remove spaces and underscores
392+
$key = str_replace([' ', '_'], '', $key);
393+
394+
// Convert camelCase to lowercase (flatten everything)
395+
$key = strtolower(preg_replace('/([a-z])([A-Z])/', '$1$2', $key));
396+
397+
return $key;
398+
}
399+
400+
401+
/**
374402
* @throws MappingFailed
375403
*/
376404
private function getMethodFirstArgument(ReflectionMethod $reflectionMethod): ReflectionParameter

src/Serializer/DenormalizerTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,50 @@ public function __construct(
6363
}
6464
}
6565

66+
public function testItFindsNormalizedColumns(): void
67+
{
68+
$records = [
69+
[
70+
'observedOn' => '2023-10-30',
71+
'temperature' => '-1.5',
72+
'place' => 'Abidjan',
73+
],
74+
[
75+
'observed_on' => '2023-10-30',
76+
'temperature' => '-3',
77+
'place' => 'Abidjan',
78+
],
79+
[
80+
'observed On' => '2023-10-30',
81+
'temperature' => '-3',
82+
'place' => 'Abidjan',
83+
],
84+
[
85+
'observedon' => '2023-10-30',
86+
'temperature' => '-3',
87+
'place' => 'Abidjan',
88+
],
89+
];
90+
91+
$class = new class (5, Place::Yamoussokro, new DateTimeImmutable()) {
92+
public function __construct(
93+
public readonly float $temperature,
94+
public readonly Place $place,
95+
#[MapCell(
96+
options: ['format' => '!Y-m-d', 'timezone' => 'Africa/Kinshasa'],
97+
)]
98+
public readonly DateTimeInterface $observedOn
99+
) {
100+
}
101+
};
102+
103+
$results = [...Denormalizer::assignAll($class::class, $records, ['observedOn', 'temperature', 'place'])];
104+
self::assertCount(4, $results);
105+
foreach ($results as $result) {
106+
self::assertInstanceOf($class::class, $result);
107+
}
108+
}
109+
66110
public function testItConvertsARecordsToAnObjectUsingRecordAttribute(): void
67111
{
68112
$record = [

0 commit comments

Comments
 (0)