Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/database/src/Mappers/SelectModelMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function map(mixed $from, mixed $to): array
$idField = $model->getQualifiedPrimaryKey();

$parsed = arr($from)
->groupBy(fn (array $data, int $i) => $idField !== null ? ($data[$idField] ?? $i) : $i)
->groupBy(fn (array $data, int|string $i) => $idField !== null ? ($data[$idField] ?? $i) : $i)
->map(fn (array $rows) => $this->normalizeFields($model, $rows))
->values();

Expand Down
13 changes: 10 additions & 3 deletions packages/mapper/src/Casters/ArrayToObjectCollectionCaster.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
namespace Tempest\Mapper\Casters;

use Tempest\Mapper\Caster;
use Tempest\Mapper\Mappers\ObjectToArrayMapper;
use Tempest\Reflection\PropertyReflector;
use Tempest\Support\Json;

final readonly class ArrayToObjectCollectionCaster implements Caster
{
Expand All @@ -18,13 +18,20 @@ public function cast(mixed $input): mixed
{
$values = [];
$iterableType = $this->property->getIterableType();
$objectCaster = new ObjectCaster($iterableType);

$caster = $iterableType->isEnum()
? new EnumCaster($iterableType->getName())
: new ObjectCaster($iterableType);

if (Json\is_valid($input)) {
$input = Json\decode($input);
}

foreach ($input as $key => $item) {
if (is_object($item) && $iterableType->matches($item::class)) {
$values[$key] = $item;
} else {
$values[$key] = $objectCaster->cast($item);
$values[$key] = $caster->cast($item);
}
}

Expand Down
25 changes: 24 additions & 1 deletion tests/Integration/Database/Mappers/SelectModelMapperTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

namespace Integration\Database\Mappers;
namespace Tests\Tempest\Integration\Database\Mappers;

use Tempest\Auth\Install\User;
use Tempest\Database\Mappers\SelectModelMapper;
Expand Down Expand Up @@ -121,6 +121,17 @@ public function test_map_user_permissions(): void
$this->assertCount(1, $users[0]->userPermissions);
}

public function test_array_of_serialized_enums(): void
{
$users = map([['id' => 1, 'roles' => json_encode(['admin', 'user'])]])
->with(SelectModelMapper::class)
->to(ObjectWithArrayEnumProperty::class);

$this->assertCount(2, $users[0]->roles);
$this->assertSame(EnumToBeMappedToArray::ADMIN, $users[0]->roles[0]);
$this->assertSame(EnumToBeMappedToArray::USER, $users[0]->roles[1]);
}

private function data(): array
{
return [
Expand Down Expand Up @@ -257,3 +268,15 @@ private function data(): array
];
}
}

final class ObjectWithArrayEnumProperty
{
/** @var \Tests\Tempest\Integration\Database\Mappers\EnumToBeMappedToArray[] */
public array $roles;
}

enum EnumToBeMappedToArray: string
{
case ADMIN = 'admin';
case USER = 'user';
}
29 changes: 29 additions & 0 deletions tests/Integration/Mapper/Mappers/ArrayToObjectMapperTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,33 @@ public function test_non_strict_values_with_magic_getter(): void

$this->assertSame('magic', $object->a);
}

public function test_map_array_of_enums(): void
{
$object = map(['roles' => ['admin', 'user']])->to(ObjectWithArrayEnumProperty::class);

$this->assertCount(2, $object->roles);
$this->assertSame(EnumToBeMappedToArray::ADMIN, $object->roles[0]);
$this->assertSame(EnumToBeMappedToArray::USER, $object->roles[1]);
}

public function test_map_array_of_serialized_enums(): void
{
$object = map(['roles' => json_encode(['admin'])])->to(ObjectWithArrayEnumProperty::class);

$this->assertCount(1, $object->roles);
$this->assertSame(EnumToBeMappedToArray::ADMIN, $object->roles[0]);
}
}

final class ObjectWithArrayEnumProperty
{
/** @var \Tests\Tempest\Integration\Mapper\Mappers\EnumToBeMappedToArray[] */
public array $roles;
}

enum EnumToBeMappedToArray: string
{
case ADMIN = 'admin';
case USER = 'user';
}
Loading