Skip to content

Commit d7740dd

Browse files
author
Alexander Miertsch
authored
Merge pull request #16 from event-engine/feature/special-key
Add special key support e. g. snake_case
2 parents 614d408 + 97ed424 commit d7740dd

File tree

4 files changed

+187
-20
lines changed

4 files changed

+187
-20
lines changed

src/ImmutableRecordLogic.php

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ public function toArray(): array
9393
$arrayPropItemTypeMap = self::getArrayPropItemTypeMapFromMethodOrCache();
9494

9595
foreach (self::$__propTypeMap as $key => [$type, $isNative, $isNullable]) {
96+
$specialKey = $key;
97+
98+
if ($this instanceof SpecialKeySupport) {
99+
$specialKey = $this->convertKeyForArray($key);
100+
}
101+
96102
switch ($type) {
97103
case ImmutableRecord::PHP_TYPE_STRING:
98104
case ImmutableRecord::PHP_TYPE_INT:
@@ -101,23 +107,23 @@ public function toArray(): array
101107
case ImmutableRecord::PHP_TYPE_ARRAY:
102108
if (\array_key_exists($key, $arrayPropItemTypeMap) && ! self::isScalarType($arrayPropItemTypeMap[$key])) {
103109
if ($isNullable && $this->{$key} === null) {
104-
$nativeData[$key] = null;
110+
$nativeData[$specialKey] = null;
105111
continue 2;
106112
}
107113

108-
$nativeData[$key] = \array_map(function ($item) use ($key, &$arrayPropItemTypeMap) {
114+
$nativeData[$specialKey] = \array_map(function ($item) use ($key, &$arrayPropItemTypeMap) {
109115
return $this->voTypeToNative($item, $key, $arrayPropItemTypeMap[$key]);
110116
}, $this->{$key});
111117
} else {
112-
$nativeData[$key] = $this->{$key};
118+
$nativeData[$specialKey] = $this->{$key};
113119
}
114120
break;
115121
default:
116122
if ($isNullable && (! isset($this->{$key}))) {
117-
$nativeData[$key] = null;
123+
$nativeData[$specialKey] = null;
118124
continue 2;
119125
}
120-
$nativeData[$key] = $this->voTypeToNative($this->{$key}, $key, $type);
126+
$nativeData[$specialKey] = $this->voTypeToNative($this->{$key}, $key, $type);
121127
}
122128
}
123129

@@ -126,7 +132,7 @@ public function toArray(): array
126132

127133
public function equals(ImmutableRecord $other): bool
128134
{
129-
if (get_class($this) !== get_class($other)) {
135+
if (\get_class($this) !== \get_class($other)) {
130136
return false;
131137
}
132138

@@ -136,8 +142,14 @@ public function equals(ImmutableRecord $other): bool
136142
private function setRecordData(array $recordData): void
137143
{
138144
foreach ($recordData as $key => $value) {
139-
$this->assertType($key, $value);
140-
$this->{$key} = $value;
145+
$specialKey = $key;
146+
147+
if ($this instanceof SpecialKeySupport) {
148+
$specialKey = $this->convertKeyForRecord($key);
149+
}
150+
151+
$this->assertType($specialKey, $value);
152+
$this->{$specialKey} = $value;
141153
}
142154
}
143155

@@ -147,17 +159,23 @@ private function setNativeData(array $nativeData): void
147159
$arrayPropItemTypeMap = self::getArrayPropItemTypeMapFromMethodOrCache();
148160

149161
foreach ($nativeData as $key => $val) {
150-
if (! isset(self::$__propTypeMap[$key])) {
162+
$specialKey = $key;
163+
164+
if ($this instanceof SpecialKeySupport) {
165+
$specialKey = $this->convertKeyForRecord($key);
166+
}
167+
168+
if (! isset(self::$__propTypeMap[$specialKey])) {
151169
throw new \InvalidArgumentException(\sprintf(
152-
'Invalid property passed to Record %s. Got property with key ' . $key,
170+
'Invalid property passed to Record %s. Got property with key ' . $specialKey,
153171
\get_called_class()
154172
));
155173
}
156-
[$type, $isNative, $isNullable] = self::$__propTypeMap[$key];
174+
[$type, $isNative, $isNullable] = self::$__propTypeMap[$specialKey];
157175

158176
if ($val === null) {
159177
if (! $isNullable) {
160-
throw new \RuntimeException("Got null for non nullable property $key of Record " . \get_called_class());
178+
throw new \RuntimeException("Got null for non nullable property $specialKey of Record " . \get_called_class());
161179
}
162180

163181
$recordData[$key] = null;

src/SpecialKeySupport.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
/**
3+
* This file is part of event-engine/php-data.
4+
* (c) 2018-2020 prooph software GmbH <contact@prooph.de>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace EventEngine\Data;
13+
14+
/**
15+
* Implement this interface in your ImmutableRecord class if you have special keys like snake_case.
16+
*/
17+
interface SpecialKeySupport
18+
{
19+
/**
20+
* Converts the given key to key name for the record. For example if the key is first_name and you have a class
21+
* property firstName then you have to convert it to camel case.
22+
*
23+
* @param string $key
24+
* @return string
25+
*/
26+
public function convertKeyForRecord(string $key): string;
27+
28+
/**
29+
* Converts the given key to key name for the array data. For example if you have a class property firstName
30+
* and want to have snake case array keys then you have to convert it to first_name.
31+
*
32+
* @param string $key
33+
* @return string
34+
*/
35+
public function convertKeyForArray(string $key): string;
36+
}

tests/ImmutableRecordLogicTest.php

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
* For the full copyright and license information, please view the LICENSE
77
* file that was distributed with this source code.
88
*/
9+
910
declare(strict_types=1);
1011

1112
namespace EventEngineTest\Data;
1213

1314
use EventEngineTest\Data\Stub\ImmutableItem;
1415
use EventEngineTest\Data\Stub\ImmutableRecordWithNoTypes;
1516
use EventEngineTest\Data\Stub\ImmutableRecordWithTypedGetters;
17+
use EventEngineTest\Data\Stub\RecordWithSpecialKey;
1618
use EventEngineTest\Data\Stub\RecordWithStringList;
1719
use EventEngineTest\Data\Stub\TypeHintedImmutableRecord;
1820
use EventEngineTest\Data\Stub\TypeHintedImmutableRecordWithValueObjects;
@@ -23,7 +25,6 @@
2325
use EventEngineTest\Data\Stub\ValueObject\Type;
2426
use EventEngineTest\Data\Stub\ValueObject\Version;
2527
use PHPUnit\Framework\TestCase;
26-
use function sprintf;
2728

2829
final class ImmutableRecordLogicTest extends TestCase
2930
{
@@ -121,7 +122,7 @@ public function it_returns_new_record_with_changed_properties()
121122

122123
$changedValueObjects = $valueObjects->with([
123124
'version' => Version::fromInt(2),
124-
'percentage' => Percentage::fromFloat(0.9)
125+
'percentage' => Percentage::fromFloat(0.9),
125126
]);
126127

127128
$this->data['type'] = null;
@@ -152,6 +153,28 @@ public function it_equals_other_record_with_same_values()
152153
$this->assertTrue($valueObjects->equals($other));
153154
}
154155

156+
/**
157+
* @test
158+
*/
159+
public function it_supports_special_keys(): void
160+
{
161+
// emulates snake_case
162+
$recordArray = [
163+
RecordWithSpecialKey::BANK_ACCOUNT => '12324434',
164+
RecordWithSpecialKey::SUCCESS_RATE => 33.33,
165+
RecordWithSpecialKey::ITEM_LIST => [['name' => 'Awesome tester'], ['name' => 'John Smith']],
166+
];
167+
$specialKey = RecordWithSpecialKey::fromArray($recordArray);
168+
$this->assertSame($recordArray, $specialKey->toArray());
169+
170+
$specialKey = RecordWithSpecialKey::fromRecordData([
171+
RecordWithSpecialKey::BANK_ACCOUNT => $recordArray[RecordWithSpecialKey::BANK_ACCOUNT],
172+
RecordWithSpecialKey::SUCCESS_RATE => Percentage::fromFloat($recordArray[RecordWithSpecialKey::SUCCESS_RATE]),
173+
RecordWithSpecialKey::ITEM_LIST => ItemList::fromArray($recordArray[RecordWithSpecialKey::ITEM_LIST]),
174+
]);
175+
$this->assertSame($recordArray, $specialKey->toArray());
176+
}
177+
155178
/**
156179
* @test
157180
*/
@@ -183,7 +206,7 @@ public function it_throws_exception_if_non_nullable_prop_should_be_set_to_null()
183206
{
184207
$this->data['version'] = null;
185208

186-
$this->expectExceptionMessage("Got null for non nullable property version of Record " . TypeHintedImmutableRecord::class);
209+
$this->expectExceptionMessage('Got null for non nullable property version of Record ' . TypeHintedImmutableRecord::class);
187210

188211
TypeHintedImmutableRecord::fromArray($this->data);
189212
}
@@ -195,8 +218,8 @@ public function it_throws_exception_if_property_value_has_wrong_type()
195218
{
196219
$this->data['version'] = 'v1';
197220

198-
$this->expectExceptionMessage(sprintf(
199-
"Record %s data contains invalid value for property version. Expected type is int. Got type string.",
221+
$this->expectExceptionMessage(\sprintf(
222+
'Record %s data contains invalid value for property version. Expected type is int. Got type string.',
200223
TypeHintedImmutableRecord::class
201224
));
202225

@@ -208,10 +231,10 @@ public function it_throws_exception_if_property_value_has_wrong_type()
208231
*/
209232
public function it_throws_exception_if_array_property_contains_invalid_value()
210233
{
211-
$stringList = ["abc", 123, "def"];
234+
$stringList = ['abc', 123, 'def'];
212235

213-
$this->expectExceptionMessage(sprintf(
214-
"Record %s data contains invalid value for property stringList. Value should be an array of string, but at least one item of the array has the wrong type.",
236+
$this->expectExceptionMessage(\sprintf(
237+
'Record %s data contains invalid value for property stringList. Value should be an array of string, but at least one item of the array has the wrong type.',
215238
RecordWithStringList::class
216239
));
217240

tests/Stub/RecordWithSpecialKey.php

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
/**
3+
* This file is part of event-engine/php-data.
4+
* (c) 2018-2020 prooph software GmbH <contact@prooph.de>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace EventEngineTest\Data\Stub;
13+
14+
use EventEngine\Data\ImmutableRecord;
15+
use EventEngine\Data\ImmutableRecordLogic;
16+
use EventEngine\Data\SpecialKeySupport;
17+
use EventEngineTest\Data\Stub\ValueObject\ItemList;
18+
use EventEngineTest\Data\Stub\ValueObject\Percentage;
19+
20+
final class RecordWithSpecialKey implements ImmutableRecord, SpecialKeySupport
21+
{
22+
use ImmutableRecordLogic;
23+
24+
public const BANK_ACCOUNT = 'bank_account';
25+
public const SUCCESS_RATE = 'success_rate';
26+
public const ITEM_LIST = 'item_list';
27+
28+
/**
29+
* @var string
30+
*/
31+
private $bankAccount;
32+
33+
/**
34+
* @var Percentage
35+
*/
36+
private $successRate;
37+
38+
/**
39+
* @var ItemList
40+
*/
41+
private $itemList;
42+
43+
/**
44+
* @return mixed
45+
*/
46+
public function bankAccount(): string
47+
{
48+
return $this->bankAccount;
49+
}
50+
51+
/**
52+
* @return Percentage
53+
*/
54+
public function successRate(): Percentage
55+
{
56+
return $this->successRate;
57+
}
58+
59+
/**
60+
* @return ItemList
61+
*/
62+
public function itemList(): ItemList
63+
{
64+
return $this->itemList;
65+
}
66+
67+
public function convertKeyForRecord(string $key): string
68+
{
69+
switch ($key) {
70+
case self::SUCCESS_RATE:
71+
return 'successRate';
72+
case self::ITEM_LIST:
73+
return 'itemList';
74+
default:
75+
return 'bankAccount';
76+
}
77+
}
78+
79+
public function convertKeyForArray(string $key): string
80+
{
81+
switch ($key) {
82+
case 'successRate':
83+
return self::SUCCESS_RATE;
84+
case 'itemList':
85+
return self::ITEM_LIST;
86+
default:
87+
return self::BANK_ACCOUNT;
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)