Skip to content

Commit

Permalink
Merge pull request #53 from hirethunk/fix-mysql-reorder-json-keys
Browse files Browse the repository at this point in the history
Fix the mysql json order bug
  • Loading branch information
DanielCoulbourne authored Jan 16, 2024
2 parents 8d3c2d1 + 46fa349 commit abc2205
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
11 changes: 9 additions & 2 deletions src/Support/Normalization/CollectionNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Thunk\Verbs\Support\Normalization;

use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use InvalidArgumentException;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
Expand All @@ -23,6 +24,7 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
{
$fqcn = data_get($data, 'fqcn', Collection::class);
$items = data_get($data, 'items', []);
$isAssoc = data_get($data, 'associative', false);

if ($items === []) {
return new $fqcn();
Expand All @@ -33,7 +35,9 @@ public function denormalize(mixed $data, string $type, ?string $format = null, a
throw new InvalidArgumentException('Cannot denormalize a Collection that has no type information.');
}

return $fqcn::make($items)->map(fn ($value) => $this->serializer->denormalize($value, $subtype, $format, $context));
return $fqcn::make($items)
->when($isAssoc, fn ($collection) => $collection->mapWithKeys(fn ($value) => [$value[0] => $value[1]]))
->map(fn ($value) => $this->serializer->denormalize($value, $subtype, $format, $context));
}

public function supportsNormalization(mixed $data, ?string $format = null): bool
Expand All @@ -50,7 +54,10 @@ public function normalize(mixed $object, ?string $format = null, array $context
return array_filter([
'fqcn' => $object::class === Collection::class ? null : $object::class,
'type' => $this->determineContainedType($object),
'items' => $object->map(fn ($value) => $this->serializer->normalize($value, $format, $context))->all(),
'items' => Arr::isAssoc($object->all())
? $object->map(fn ($value, $key) => [$key, $this->serializer->normalize($value, $format, $context)])->values()->all()
: $object->map(fn ($value) => $this->serializer->normalize($value, $format, $context))->values()->all(),
'associative' => Arr::isAssoc($object->all()),
]);
}

Expand Down
31 changes: 31 additions & 0 deletions tests/Unit/CollectionNormalizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,37 @@
}
});

it('can normalize a collection with keys and restore key order', function () {
$collection = Collection::make([
2 => 2,
1 => 1,
3 => 3,
]);

$expected_json = '{"type":"int","items":[[2,2],[1,1],[3,3]],"associative":true}';

$serializer = new SymfonySerializer(
normalizers: [$normalizer = new CollectionNormalizer()],
encoders: [new JsonEncoder()],
);

// We should be able to normalize
expect($normalizer->supportsNormalization($collection))->toBeTrue();
$normalized = $serializer->normalize($collection, 'json');

// And encode to JSON
$encoded = json_encode($normalized);
expect($encoded)->toBe($expected_json);

// And then denormalize that JSON
expect($normalizer->supportsDenormalization($encoded, Collection::class, 'json'))->toBeTrue();
$denormalized = $serializer->denormalize(json_decode($encoded), Collection::class);

// And the denormalized data should be the same
expect($denormalized)->toBeInstanceOf(Collection::class);
expect($denormalized->all())->toBe($collection->all());
});

it('can normalize a collection all of states', function () {
$manager = app(StateManager::class);

Expand Down

0 comments on commit abc2205

Please sign in to comment.