Skip to content

Commit 02da3d2

Browse files
committed
fix: tranformation case issue
1 parent 41e7ddf commit 02da3d2

6 files changed

Lines changed: 94 additions & 17 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,9 @@ readonly class CreateUserData extends DataTransferObject
550550

551551
/**
552552
* Apply data transformations
553+
*
554+
* Note: Transform keys support both camelCase and snake_case.
555+
* Use camelCase (firstName) or snake_case (first_name) - both work!
553556
*/
554557
protected static function transforms(): array
555558
{

src/Actions/Filesystem/FilePresentAction.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function execute(FilePresentData $data, bool $withForce = false): bool
2323
}
2424

2525
if ($filesystem->exists(path: $path)) {
26-
return throw new FileAlreadyExistException($data->fileName);
26+
throw new FileAlreadyExistException($data->fileName);
2727
}
2828

2929
return false;

src/Foundation/DataTransferObject.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ public function get(string $property, mixed $default = null): mixed
116116
}
117117

118118
/**
119-
* Convert DTO to JSON
119+
* Convert DTO to snake_case JSON
120+
*
121+
* @throws \JsonException
120122
*/
121123
public function toJson(int $options = 0): string
122124
{
@@ -129,6 +131,22 @@ public function toJson(int $options = 0): string
129131
return $json;
130132
}
131133

134+
/**
135+
* Convert DTO to camelCase JSON
136+
*
137+
* @throws \JsonException
138+
*/
139+
public function toCamelJson(int $options = 0): string
140+
{
141+
$json = json_encode($this->toCamelCase(), $options);
142+
143+
if ($json === false) {
144+
throw new \JsonException('Failed to encode DTO to JSON');
145+
}
146+
147+
return $json;
148+
}
149+
132150
/**
133151
* Convert DTO to camelCase array
134152
*
@@ -244,8 +262,6 @@ private function getPropertyValue(\ReflectionProperty $property): mixed
244262
return null;
245263
}
246264

247-
$property->setAccessible(true);
248-
249265
return $property->getValue($this);
250266
}
251267

src/Foundation/DataTransferObject/HasResolvable.php

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace Holiq\ActionData\Foundation\DataTransferObject;
44

55
use CuyZ\Valinor\Mapper\MappingError;
6-
use CuyZ\Valinor\MapperBuilder;
6+
use CuyZ\Valinor\Mapper\TreeMapper;
77
use Holiq\ActionData\Exceptions\InvalidArgumentException;
88
use Illuminate\Database\Eloquent\Model;
99
use Illuminate\Foundation\Http\FormRequest;
@@ -37,7 +37,7 @@ public static function resolveFrom(mixed $abstract): static
3737
}
3838

3939
throw new InvalidArgumentException(
40-
'Unsupported data type for DTO resolution. Expected FormRequest, Model, or array, got: ' . get_debug_type($abstract)
40+
'Unsupported data type for DTO resolution. Expected FormRequest, Model, or array, got: ' . get_debug_type($abstract),
4141
);
4242
}
4343

@@ -56,13 +56,20 @@ public static function resolve(array $data): static
5656
$data = static::applyTransforms($data);
5757

5858
/** @var static $instance */
59-
$instance = (new MapperBuilder())
60-
->mapper()
59+
$instance = static::mapper()
6160
->map(signature: static::class, source: static::resolveTheArrayKeyForm(data: $data));
6261

6362
return $instance;
6463
}
6564

65+
/**
66+
* Get the mapper instance
67+
*/
68+
protected static function mapper(): TreeMapper
69+
{
70+
return MapperRegistry::getMapper();
71+
}
72+
6673
/**
6774
* Apply data transformations
6875
*
@@ -77,8 +84,25 @@ protected static function applyTransforms(array $data): array
7784
$transforms = static::transforms();
7885

7986
foreach ($transforms as $key => $transform) {
87+
// Try exact key match first
8088
if (array_key_exists($key, $data)) {
8189
$data[$key] = $transform($data[$key]);
90+
91+
continue;
92+
}
93+
94+
// Try snake_case version of the key (for camelCase transform keys)
95+
$snakeKey = Str::snake($key);
96+
if ($snakeKey !== $key && array_key_exists($snakeKey, $data)) {
97+
$data[$snakeKey] = $transform($data[$snakeKey]);
98+
99+
continue;
100+
}
101+
102+
// Try camelCase version of the key (for snake_case transform keys)
103+
$camelKey = Str::camel($key);
104+
if ($camelKey !== $key && array_key_exists($camelKey, $data)) {
105+
$data[$camelKey] = $transform($data[$camelKey]);
82106
}
83107
}
84108

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Holiq\ActionData\Foundation\DataTransferObject;
4+
5+
use CuyZ\Valinor\Mapper\TreeMapper;
6+
use CuyZ\Valinor\MapperBuilder;
7+
8+
class MapperRegistry
9+
{
10+
private static ?TreeMapper $mapperInstance = null;
11+
12+
/**
13+
* Get the TreeMapper instance
14+
*/
15+
public static function getMapper(): TreeMapper
16+
{
17+
return self::$mapperInstance ??= (new MapperBuilder())->mapper();
18+
}
19+
20+
/**
21+
* Reset the TreeMapper instance
22+
*/
23+
public static function resetMapper(): void
24+
{
25+
self::$mapperInstance = null;
26+
}
27+
}

tests/Unit/DataTransferObjectTest.php

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ public function __construct(
5959
$data = new TestUserData(
6060
firstName: 'John',
6161
lastName: 'Doe',
62-
email: 'john@example.com'
62+
email: 'john@example.com',
63+
password: 'secret123'
6364
);
6465

6566
$array = $data->toArray();
@@ -68,7 +69,7 @@ public function __construct(
6869
'first_name' => 'John',
6970
'last_name' => 'Doe',
7071
'email' => 'john@example.com',
71-
'password' => null,
72+
'password' => 'secret123',
7273
]);
7374
});
7475

@@ -136,14 +137,20 @@ public function __construct(
136137
);
137138

138139
$json = $data->toJson();
139-
$decoded = json_decode($json, true);
140140

141-
expect($decoded)->toBe([
142-
'first_name' => 'John',
143-
'last_name' => 'Doe',
144-
'email' => 'john@example.com',
145-
'password' => null,
146-
]);
141+
expect($json)->toBeJson();
142+
});
143+
144+
it('can convert to camelCase JSON', function () {
145+
$data = new TestUserData(
146+
firstName: 'John',
147+
lastName: 'Doe',
148+
email: 'john@example.com'
149+
);
150+
151+
$json = $data->toCamelJson();
152+
153+
expect($json)->toBeJson();
147154
});
148155

149156
it('can convert to camelCase array', function () {

0 commit comments

Comments
 (0)