Skip to content

Commit 6ad371a

Browse files
authored
Merge pull request #9 from emulgeator/special-character-handling
Handing special characters in key names
2 parents 4f5b0fa + 8d53bdb commit 6ad371a

File tree

3 files changed

+65
-33
lines changed

3 files changed

+65
-33
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
## [0.2.0] - 2024-03-05
9+
10+
### Added
11+
- When a key in the input array has a special character, the library will try to find the property by removing the special characters
12+
813
## [0.1.4] - 2023-11-16
914

1015
### Fixed

src/Mapper.php

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?php
2+
23
declare(strict_types=1);
34

45
namespace Emul\ArrayToClassMapper;
@@ -27,6 +28,11 @@ public function addCustomMapper(string $type, Closure $mapper)
2728
$this->customMappers[$type] = $mapper;
2829
}
2930

31+
public function removeSpecialCharacters(string $key): string
32+
{
33+
return preg_replace('#[^A-Za-z0-9_]#', '', $key);
34+
}
35+
3036
public function getCustomMapper(string $type): ?Closure
3137
{
3238
$type = $this->formatCustomTypeName($type);
@@ -40,10 +46,11 @@ public function map(array $input, string $className)
4046
{
4147
$object = (new ReflectionClass($className))->newInstanceWithoutConstructor();
4248
$reflectionClass = (new ReflectionClass($object));
43-
4449
$classProperties = $reflectionClass->getProperties();
4550

4651
foreach ($input as $key => $value) {
52+
$key = $this->removeSpecialCharacters($key);
53+
4754
foreach ($classProperties as $property) {
4855
if ($key !== $property->getName()) {
4956
continue;
@@ -55,37 +62,9 @@ public function map(array $input, string $className)
5562
$type = $property->getType();
5663

5764
if (!empty($type)) {
58-
if ($type->isBuiltin()) {
59-
if ($type->getName() === 'array') {
60-
if (empty($docBlockType)) {
61-
$property->setValue($object, $value);
62-
} else {
63-
$valueCasted = is_null($value) ? null : $this->castArray($value, $docBlockType);
64-
$property->setValue($object, $valueCasted);
65-
}
66-
} else {
67-
$property->setValue($object, $value);
68-
}
69-
} else {
70-
$this->setCustomValue($object, $property, $type->getName(), $value);
71-
}
65+
$this->setValueByPhpType($type, $docBlockType, $property, $object, $value);
7266
} else {
73-
if (empty($docBlockType)) {
74-
$property->setValue($object, $value);
75-
} else {
76-
if ($docBlockType->isBuiltIn()) {
77-
if ($docBlockType->getName() === 'array') {
78-
$property->setValue($object, $this->castArray($value, $docBlockType));
79-
} else {
80-
settype($value, $docBlockType->getName());
81-
$property->setValue($object, $value);
82-
}
83-
} elseif (!$docBlockType->isSingle()) {
84-
$property->setValue($object, $this->castArray($value, $docBlockType));
85-
} else {
86-
$this->setCustomValue($object, $property, $docBlockType->getName(), $value);
87-
}
88-
}
67+
$this->setValueByDocBlock($docBlockType, $property, $object, $value);
8968
}
9069
}
9170
}
@@ -100,8 +79,7 @@ private function setCustomValue($object, \ReflectionProperty $property, string $
10079
&& empty($this->getCustomMapper($typeName))
10180
) {
10281
$property->setValue($object, null);
103-
}
104-
else {
82+
} else {
10583
$property->setValue($object, $this->castCustom($value, $typeName));
10684
}
10785
}
@@ -146,4 +124,42 @@ private function formatCustomTypeName(string $type): string
146124
{
147125
return ltrim($type, '\\');
148126
}
127+
128+
private function setValueByPhpType(\ReflectionNamedType $type, ?DocBlockType $docBlockType, \ReflectionProperty $property, $object, $value): void
129+
{
130+
if ($type->isBuiltin()) {
131+
if ($type->getName() === 'array') {
132+
if (empty($docBlockType)) {
133+
$property->setValue($object, $value);
134+
} else {
135+
$valueCasted = is_null($value) ? null : $this->castArray($value, $docBlockType);
136+
$property->setValue($object, $valueCasted);
137+
}
138+
} else {
139+
$property->setValue($object, $value);
140+
}
141+
} else {
142+
$this->setCustomValue($object, $property, $type->getName(), $value);
143+
}
144+
}
145+
146+
private function setValueByDocBlock(?DocBlockType $docBlockType, \ReflectionProperty $property, $object, $value): void
147+
{
148+
if (empty($docBlockType)) {
149+
$property->setValue($object, $value);
150+
} else {
151+
if ($docBlockType->isBuiltIn()) {
152+
if ($docBlockType->getName() === 'array') {
153+
$property->setValue($object, $this->castArray($value, $docBlockType));
154+
} else {
155+
settype($value, $docBlockType->getName());
156+
$property->setValue($object, $value);
157+
}
158+
} elseif (!$docBlockType->isSingle()) {
159+
$property->setValue($object, $this->castArray($value, $docBlockType));
160+
} else {
161+
$this->setCustomValue($object, $property, $docBlockType->getName(), $value);
162+
}
163+
}
164+
}
149165
}

test/Unit/MapperTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ public function testMapWhenNullGiven_shouldSet()
4141
$this->assertNull($result->getInt());
4242
}
4343

44+
public function testMapWhenKeyContainsSpecialCharacter_shouldSetByRemovingSpecialChars()
45+
{
46+
$mapper = $this->getMapper();
47+
$input = ['@int' => 12];
48+
49+
/** @var ScalarTypedStub $result */
50+
$result = $mapper->map($input, ScalarTypedStub::class);
51+
52+
$this->assertSame(12, $result->getInt());
53+
}
54+
4455
public function testMapWhenBuiltInTypedPropertyGiven_shouldCast()
4556
{
4657
$mapper = $this->getMapper();

0 commit comments

Comments
 (0)