Skip to content

Commit 3300c1f

Browse files
committed
feat: dissociate mapper and database data transfer object mapping
1 parent 095ce99 commit 3300c1f

20 files changed

+89
-584
lines changed

packages/database/src/Builder/QueryBuilders/SelectQueryBuilder.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public function first(mixed ...$bindings): mixed
9595

9696
$result = map($query->fetch())
9797
->with(SelectModelMapper::class)
98+
->in($this->context)
9899
->to($this->model->getName());
99100

100101
if ($result === []) {

packages/mapper/src/Casters/DataTransferObjectCaster.php renamed to packages/database/src/Casters/DataTransferObjectCaster.php

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
11
<?php
22

3-
namespace Tempest\Mapper\Casters;
3+
namespace Tempest\Database\Casters;
44

5+
use Closure;
56
use Tempest\Core\Priority;
7+
use Tempest\Database\DatabaseContext;
8+
use Tempest\Mapper\Attributes\Context;
69
use Tempest\Mapper\Caster;
10+
use Tempest\Mapper\Context as MapperContext;
711
use Tempest\Mapper\Exceptions\ValueCouldNotBeCast;
812
use Tempest\Mapper\MapperConfig;
13+
use Tempest\Mapper\SerializeAs;
14+
use Tempest\Reflection\TypeReflector;
915
use Tempest\Support\Arr;
1016
use Tempest\Support\Json;
1117

1218
use function Tempest\Mapper\map;
1319

14-
#[Priority(Priority::LOW)]
20+
#[Priority(Priority::HIGHEST)]
21+
#[Context(DatabaseContext::class)]
1522
final readonly class DataTransferObjectCaster implements Caster
1623
{
1724
public function __construct(
1825
private MapperConfig $mapperConfig,
26+
private MapperContext $context,
1927
) {}
2028

21-
public static function for(): false
29+
public static function for(): Closure
2230
{
23-
return false; // this caster is always applied manually
31+
return fn (TypeReflector $type) => $type->isClass() && $type->asClass()->getAttribute(SerializeAs::class);
2432
}
2533

2634
public function cast(mixed $input): mixed
@@ -48,7 +56,9 @@ private function deserialize(mixed $input): mixed
4856
value: $input['type'],
4957
) ?: $input['type'];
5058

51-
return map($this->deserialize($input['data']))->to($class);
59+
return map($this->deserialize($input['data']))
60+
->in($this->context)
61+
->to($class);
5262
}
5363

5464
if (is_array($input)) {

packages/mapper/src/Serializers/DataTransferObjectSerializer.php renamed to packages/database/src/Serializers/DataTransferObjectSerializer.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,39 @@
11
<?php
22

3-
namespace Tempest\Mapper\Serializers;
3+
namespace Tempest\Database\Serializers;
44

55
use BackedEnum;
6+
use Closure;
67
use JsonSerializable;
8+
use Tempest\Core\Priority;
9+
use Tempest\Database\DatabaseContext;
10+
use Tempest\Mapper\Attributes\Context;
711
use Tempest\Mapper\Exceptions\ValueCouldNotBeSerialized;
812
use Tempest\Mapper\MapperConfig;
13+
use Tempest\Mapper\SerializeAs;
914
use Tempest\Mapper\Serializer;
1015
use Tempest\Reflection\ClassReflector;
1116
use Tempest\Reflection\PropertyReflector;
17+
use Tempest\Reflection\TypeReflector;
1218
use Tempest\Support\Arr;
1319
use Tempest\Support\Json;
1420
use UnitEnum;
1521

22+
#[Priority(Priority::HIGHEST)]
23+
#[Context(DatabaseContext::class)]
1624
final readonly class DataTransferObjectSerializer implements Serializer
1725
{
1826
public function __construct(
1927
private MapperConfig $mapperConfig,
2028
) {}
2129

22-
public static function for(): false
30+
public static function for(): Closure
2331
{
24-
return false;
32+
return fn (TypeReflector $type) => $type->isClass() && $type->asClass()->getAttribute(SerializeAs::class);
2533
}
2634

2735
public function serialize(mixed $input): array|string
2836
{
29-
// Support top-level arrays
3037
if (is_array($input)) {
3138
return Json\encode($this->serializeWithType($input));
3239
}

packages/mapper/src/CasterFactory.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use Closure;
88
use Tempest\Container\Container;
99
use Tempest\Container\Singleton;
10-
use Tempest\Mapper\Casters\DataTransferObjectCaster;
1110
use Tempest\Reflection\FunctionReflector;
1211
use Tempest\Reflection\PropertyReflector;
1312
use Tempest\Reflection\TypeReflector;
@@ -61,10 +60,6 @@ public function forProperty(PropertyReflector $property): ?Caster
6160

6261
if ($castWith === null && $type->isClass()) {
6362
$castWith = $type->asClass()->getAttribute(CastWith::class, recursive: true);
64-
65-
if ($castWith === null && $type->asClass()->getAttribute(SerializeAs::class)) {
66-
return $this->container->get(DataTransferObjectCaster::class, context: $context);
67-
}
6863
}
6964

7065
if ($castWith) {

packages/mapper/src/Mappers/ObjectToArrayMapper.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ private function resolvePropertyValue(PropertyReflector $property, object $objec
7171
return $serializer->serialize($propertyValue);
7272
}
7373

74+
// if (is_object($propertyValue)) {
75+
// return map($propertyValue)->toArray();
76+
// }
77+
7478
return $propertyValue;
7579
}
7680

packages/mapper/src/SerializerFactory.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use Closure;
88
use Tempest\Container\Container;
99
use Tempest\Container\Singleton;
10-
use Tempest\Mapper\Serializers\DataTransferObjectSerializer;
1110
use Tempest\Reflection\ClassReflector;
1211
use Tempest\Reflection\PropertyReflector;
1312
use Tempest\Reflection\TypeReflector;
@@ -62,10 +61,6 @@ public function forProperty(PropertyReflector $property): ?Serializer
6261

6362
if ($serializeWith === null && $type->isClass()) {
6463
$serializeWith = $type->asClass()->getAttribute(SerializeWith::class, recursive: true);
65-
66-
if ($serializeWith === null && $type->asClass()->getAttribute(SerializeAs::class)) {
67-
$serializeWith = new SerializeWith(DataTransferObjectSerializer::class);
68-
}
6964
}
7065

7166
if ($serializeWith !== null) {

tests/Integration/Database/Builder/UpdateQueryBuilderDtoTest.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ final class UpdateQueryBuilderDtoTest extends FrameworkIntegrationTestCase
1717
{
1818
public function test_update_with_serialize_as_dto(): void
1919
{
20-
$this->migrate(CreateMigrationsTable::class, new class implements MigratesUp {
20+
$this->database->migrate(CreateMigrationsTable::class, new class implements MigratesUp {
2121
public string $name = '001_create_users_table_for_dto_update';
2222

2323
public function up(): QueryStatement
@@ -29,11 +29,10 @@ public function up(): QueryStatement
2929
}
3030
});
3131

32-
$user = query(UserWithDtoSettings::class)
33-
->create(
34-
name: 'John',
35-
settings: new DtoSettings(DtoTheme::LIGHT),
36-
);
32+
$user = query(UserWithDtoSettings::class)->create(
33+
name: 'John',
34+
settings: new DtoSettings(DtoTheme::LIGHT),
35+
);
3736

3837
query(UserWithDtoSettings::class)
3938
->update(

tests/Integration/Database/DtoSerialization/BasicDtoSerializationTest.php

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@
88
use Tempest\Database\Migrations\CreateMigrationsTable;
99
use Tempest\Database\QueryStatement;
1010
use Tempest\Database\QueryStatements\CreateTableStatement;
11-
use Tempest\Mapper\Casters\DataTransferObjectCaster;
12-
use Tempest\Mapper\CastWith;
1311
use Tempest\Mapper\SerializeAs;
14-
use Tempest\Mapper\Serializers\DataTransferObjectSerializer;
15-
use Tempest\Mapper\SerializeWith;
1612
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
1713

1814
use function Tempest\Database\query;
@@ -191,8 +187,7 @@ public function __construct(
191187
) {}
192188
}
193189

194-
#[CastWith(DataTransferObjectCaster::class)]
195-
#[SerializeWith(DataTransferObjectSerializer::class)]
190+
#[SerializeAs(self::class)]
196191
final class CharacterStats
197192
{
198193
public function __construct(
@@ -210,8 +205,7 @@ public function __construct(
210205
) {}
211206
}
212207

213-
#[CastWith(DataTransferObjectCaster::class)]
214-
#[SerializeWith(DataTransferObjectSerializer::class)]
208+
#[SerializeAs(self::class)]
215209
final class ClassDetails
216210
{
217211
public function __construct(
@@ -229,8 +223,6 @@ public function __construct(
229223
) {}
230224
}
231225

232-
#[CastWith(DataTransferObjectCaster::class)]
233-
#[SerializeWith(DataTransferObjectSerializer::class)]
234226
#[SerializeAs('app-settings')]
235227
final class ApplicationSettings
236228
{

tests/Integration/Database/DtoSerialization/NestedDtoSerializationTest.php

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@
88
use Tempest\Database\Migrations\CreateMigrationsTable;
99
use Tempest\Database\QueryStatement;
1010
use Tempest\Database\QueryStatements\CreateTableStatement;
11-
use Tempest\Mapper\Casters\DataTransferObjectCaster;
12-
use Tempest\Mapper\CastWith;
13-
use Tempest\Mapper\Serializers\DataTransferObjectSerializer;
14-
use Tempest\Mapper\SerializeWith;
11+
use Tempest\Mapper\SerializeAs;
1512
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
1613

1714
use function Tempest\Database\query;
@@ -201,8 +198,7 @@ public function __construct(
201198
) {}
202199
}
203200

204-
#[CastWith(DataTransferObjectCaster::class)]
205-
#[SerializeWith(DataTransferObjectSerializer::class)]
201+
#[SerializeAs(self::class)]
206202
final class SpellStructure
207203
{
208204
public function __construct(
@@ -211,8 +207,7 @@ public function __construct(
211207
) {}
212208
}
213209

214-
#[CastWith(DataTransferObjectCaster::class)]
215-
#[SerializeWith(DataTransferObjectSerializer::class)]
210+
#[SerializeAs(self::class)]
216211
final class Incantation
217212
{
218213
public function __construct(
@@ -221,8 +216,7 @@ public function __construct(
221216
) {}
222217
}
223218

224-
#[CastWith(DataTransferObjectCaster::class)]
225-
#[SerializeWith(DataTransferObjectSerializer::class)]
219+
#[SerializeAs(self::class)]
226220
final class Pronunciation
227221
{
228222
public function __construct(
@@ -231,8 +225,7 @@ public function __construct(
231225
) {}
232226
}
233227

234-
#[CastWith(DataTransferObjectCaster::class)]
235-
#[SerializeWith(DataTransferObjectSerializer::class)]
228+
#[SerializeAs(self::class)]
236229
final class EmphasisPattern
237230
{
238231
public function __construct(
@@ -242,8 +235,7 @@ public function __construct(
242235
) {}
243236
}
244237

245-
#[CastWith(DataTransferObjectCaster::class)]
246-
#[SerializeWith(DataTransferObjectSerializer::class)]
238+
#[SerializeAs(self::class)]
247239
final class SpellComponents
248240
{
249241
public function __construct(
@@ -253,8 +245,7 @@ public function __construct(
253245
) {}
254246
}
255247

256-
#[CastWith(DataTransferObjectCaster::class)]
257-
#[SerializeWith(DataTransferObjectSerializer::class)]
248+
#[SerializeAs(self::class)]
258249
final class MaterialComponent
259250
{
260251
public function __construct(
@@ -264,8 +255,7 @@ public function __construct(
264255
) {}
265256
}
266257

267-
#[CastWith(DataTransferObjectCaster::class)]
268-
#[SerializeWith(DataTransferObjectSerializer::class)]
258+
#[SerializeAs(self::class)]
269259
final class ItemProperties
270260
{
271261
public function __construct(
@@ -282,8 +272,7 @@ public function __construct(
282272
) {}
283273
}
284274

285-
#[CastWith(DataTransferObjectCaster::class)]
286-
#[SerializeWith(DataTransferObjectSerializer::class)]
275+
#[SerializeAs(self::class)]
287276
final class GrimoireMetadata
288277
{
289278
public function __construct(
@@ -293,8 +282,7 @@ public function __construct(
293282
) {}
294283
}
295284

296-
#[CastWith(DataTransferObjectCaster::class)]
297-
#[SerializeWith(DataTransferObjectSerializer::class)]
285+
#[SerializeAs(self::class)]
298286
final class Author
299287
{
300288
public function __construct(
@@ -304,8 +292,7 @@ public function __construct(
304292
) {}
305293
}
306294

307-
#[CastWith(DataTransferObjectCaster::class)]
308-
#[SerializeWith(DataTransferObjectSerializer::class)]
295+
#[SerializeAs(self::class)]
309296
final class GrimoireContents
310297
{
311298
public function __construct(
@@ -316,8 +303,7 @@ public function __construct(
316303
) {}
317304
}
318305

319-
#[CastWith(DataTransferObjectCaster::class)]
320-
#[SerializeWith(DataTransferObjectSerializer::class)]
306+
#[SerializeAs(self::class)]
321307
final class IndexingSystem
322308
{
323309
public function __construct(
@@ -327,8 +313,7 @@ public function __construct(
327313
) {}
328314
}
329315

330-
#[CastWith(DataTransferObjectCaster::class)]
331-
#[SerializeWith(DataTransferObjectSerializer::class)]
316+
#[SerializeAs(self::class)]
332317
final class PreservationInfo
333318
{
334319
public function __construct(

tests/Integration/Database/DtoSerialization/TopLevelArraySerializationTest.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44

55
namespace Tests\Tempest\Integration\Database\DtoSerialization;
66

7+
use Tempest\Database\Casters\DataTransferObjectCaster;
78
use Tempest\Database\MigratesUp;
89
use Tempest\Database\Migrations\CreateMigrationsTable;
910
use Tempest\Database\QueryStatement;
1011
use Tempest\Database\QueryStatements\CreateTableStatement;
11-
use Tempest\Mapper\Casters\DataTransferObjectCaster;
12+
use Tempest\Database\Serializers\DataTransferObjectSerializer;
1213
use Tempest\Mapper\CastWith;
13-
use Tempest\Mapper\Serializers\DataTransferObjectSerializer;
14+
use Tempest\Mapper\SerializeAs;
1415
use Tempest\Mapper\SerializeWith;
1516
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
1617

@@ -138,11 +139,13 @@ public function up(): QueryStatement
138139
{
139140
public function __construct(
140141
public string $name,
141-
#[SerializeWith(DataTransferObjectSerializer::class), CastWith(DataTransferObjectCaster::class)]
142+
#[SerializeWith(DataTransferObjectSerializer::class)]
143+
#[CastWith(DataTransferObjectCaster::class)]
142144
public array $data,
143145
) {}
144146
}
145147

148+
#[SerializeAs(self::class)]
146149
final readonly class SimpleArrayItem
147150
{
148151
public function __construct(
@@ -151,6 +154,7 @@ public function __construct(
151154
) {}
152155
}
153156

157+
#[SerializeAs(self::class)]
154158
final readonly class ItemWithNestedArray
155159
{
156160
public function __construct(

0 commit comments

Comments
 (0)