Skip to content

Commit f4efcf3

Browse files
committed
add Normalizer
1 parent 081c277 commit f4efcf3

File tree

9 files changed

+183
-0
lines changed

9 files changed

+183
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Astral\Serialize\Casts\Normalizer;
4+
5+
use Astral\Serialize\Contracts\Normalizer\NormalizerCastInterface;
6+
7+
class ArrayNormalizerCast implements NormalizerCastInterface
8+
{
9+
public function match(mixed $values): bool
10+
{
11+
return is_object($values) && method_exists($values, 'toArray');
12+
}
13+
14+
public function resolve(mixed $values): mixed
15+
{
16+
if($this->match($values)){
17+
return $values->toArray();
18+
}
19+
20+
return $values;
21+
}
22+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Astral\Serialize\Casts\Normalizer;
4+
5+
use Astral\Serialize\Contracts\Normalizer\NormalizerCastInterface;
6+
use JsonException;
7+
8+
class JsonNormalizerCast implements NormalizerCastInterface
9+
{
10+
public function match(mixed $values): bool
11+
{
12+
return is_string($values);
13+
}
14+
15+
public function resolve(mixed $values): array
16+
{
17+
if($this->match($values)){
18+
try {
19+
$decoded = json_decode($values, true, 512, JSON_THROW_ON_ERROR);
20+
return is_array($decoded) ? $decoded : $values;
21+
} catch (JsonException $e) {
22+
23+
}
24+
}
25+
26+
return $values;
27+
}
28+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Astral\Serialize\Contracts\Normalizer;
4+
5+
interface NormalizerCastInterface
6+
{
7+
public function match(mixed $values): bool;
8+
9+
public function resolve(mixed $values): mixed;
10+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Astral\Serialize\Resolvers\Casts;
4+
5+
use Astral\Serialize\Support\Collections\DataCollection;
6+
use Astral\Serialize\Support\Config\ConfigManager;
7+
use Astral\Serialize\Support\Context\InputValueContext;
8+
9+
class NormalizerCastResolver
10+
{
11+
public function __construct(
12+
private readonly ConfigManager $configManager
13+
) {
14+
15+
}
16+
17+
public function resolve(mixed $values): mixed
18+
{
19+
foreach ($this->configManager->getNormalizerCasts() as $cast) {
20+
$values = $cast->resolve($values);
21+
}
22+
23+
return $values;
24+
}
25+
}

src/SerializeContainer.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Astral\Serialize\Faker\Rule\FakerDefaultRules;
99
use Astral\Serialize\Resolvers\Casts\DataCollectionCastResolver;
1010
use Astral\Serialize\Resolvers\Casts\InputValueCastResolver;
11+
use Astral\Serialize\Resolvers\Casts\NormalizerCastResolver;
1112
use Astral\Serialize\Resolvers\Casts\OutputCastResolver;
1213
use Astral\Serialize\Resolvers\GroupResolver;
1314
use Astral\Serialize\Resolvers\InputResolver;
@@ -41,6 +42,7 @@ class SerializeContainer
4142
protected ?GroupResolver $groupResolver = null;
4243
protected ?ReflectionClassInstanceManager $reflectionClassInstanceManager = null;
4344
protected ?SerializeInstanceManager $serializeInstanceManager = null;
45+
protected ?NormalizerCastResolver $normalizerCastResolver = null;
4446
protected ?DataCollectionCastResolver $attributePropertyResolver = null;
4547
protected ?InputResolver $propertyInputValueResolver = null;
4648
protected ?OutputResolver $propertyToArrayResolver = null;
@@ -119,6 +121,11 @@ public function propertyInputValueResolver(): InputResolver
119121
);
120122
}
121123

124+
public function normalizerCastResolver(): NormalizerCastResolver
125+
{
126+
return $this->normalizerCastResolver ??= new NormalizerCastResolver(ConfigManager::getInstance());
127+
}
128+
122129
public function inputValueCastResolver(): InputValueCastResolver
123130
{
124131
return $this->inputValueCastResolver ??= new InputValueCastResolver(ConfigManager::getInstance());

src/Support/Config/ConfigManager.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
use Astral\Serialize\Casts\InputValue\InputObjectBestMatchChildCast;
88
use Astral\Serialize\Casts\InputValue\InputValueEnumCast;
99
use Astral\Serialize\Casts\InputValue\InputValueNullCast;
10+
use Astral\Serialize\Casts\Normalizer\ArrayNormalizerCast;
11+
use Astral\Serialize\Casts\Normalizer\JsonNormalizerCast;
1012
use Astral\Serialize\Casts\OutValue\OutArrayChildCast;
1113
use Astral\Serialize\Casts\OutValue\OutValueEnumCast;
1214
use Astral\Serialize\Casts\OutValue\OutValueGetterCast;
1315
use Astral\Serialize\Contracts\Attribute\DataCollectionCastInterface;
1416
use Astral\Serialize\Contracts\Attribute\InputValueCastInterface;
1517
use Astral\Serialize\Contracts\Attribute\OutValueCastInterface;
18+
use Astral\Serialize\Contracts\Normalizer\NormalizerCastInterface;
1619
use Astral\Serialize\Enums\CacheDriverEnum;
1720
use Astral\Serialize\Exceptions\NotFoundAttributePropertyResolver;
1821
use Astral\Serialize\Support\Caching\MemoryCache;
@@ -40,6 +43,12 @@ class ConfigManager
4043
OutValueGetterCast::class,
4144
];
4245

46+
/** @var (NormalizerCastInterface|string)[] $normalizerCasts */
47+
private array $normalizerCasts = [
48+
// JsonNormalizerCast::class,
49+
ArrayNormalizerCast::class,
50+
];
51+
4352
/** @var CacheDriverEnum|class-string $cacheDriver */
4453
private string|CacheDriverEnum $cacheDriver = MemoryCache::class;
4554

@@ -52,13 +61,30 @@ public function __construct()
5261
foreach ($this->outputValueCasts as $key => $cast) {
5362
$this->outputValueCasts[$key] = new $cast();
5463
}
64+
65+
foreach ($this->normalizerCasts as $key => $cast) {
66+
$this->normalizerCasts[$key] = new $cast();
67+
}
5568
}
5669

5770
public static function getInstance(): ConfigManager
5871
{
5972
return self::$instance ??= new self();
6073
}
6174

75+
/**
76+
* @throws NotFoundAttributePropertyResolver
77+
*/
78+
public function addNormalizerCasts(NormalizerCastInterface|string $resolverClass): static
79+
{
80+
if (is_string($resolverClass) && !is_subclass_of($resolverClass, NormalizerCastInterface::class)) {
81+
throw new NotFoundAttributePropertyResolver('Resolver class must be an instance of NormalizerCastInterface');
82+
}
83+
$this->attributePropertyResolver[] = (is_string($resolverClass) ? new $resolverClass() : $resolverClass);
84+
85+
return $this;
86+
}
87+
6288
/**
6389
* @throws NotFoundAttributePropertyResolver
6490
*/
@@ -113,6 +139,11 @@ public function getOutValueCasts(): array
113139
return $this->outputValueCasts;
114140
}
115141

142+
public function getNormalizerCasts(): array
143+
{
144+
return $this->normalizerCasts;
145+
}
146+
116147
public function getCacheDriver(): string
117148
{
118149
if ($this->cacheDriver instanceof CacheDriverEnum) {

src/Support/Context/SerializeContext.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Astral\Serialize\Exceptions\NotFoundGroupException;
66
use Astral\Serialize\Faker\FakerResolver;
77
use Astral\Serialize\Resolvers\Casts\DataCollectionCastResolver;
8+
use Astral\Serialize\Resolvers\Casts\NormalizerCastResolver;
89
use Astral\Serialize\Resolvers\GroupResolver;
910
use Astral\Serialize\Resolvers\InputResolver;
1011
use Astral\Serialize\Resolvers\OutputResolver;
@@ -38,6 +39,7 @@ public function __construct(
3839
private readonly InputResolver $propertyInputValueResolver,
3940
private readonly OutputResolver $propertyToArrayResolver,
4041
private readonly FakerResolver $fakerResolver,
42+
private readonly NormalizerCastResolver $normalizerCastResolver,
4143
) {
4244

4345
}
@@ -187,8 +189,10 @@ className: $type->className,
187189
*/
188190
public function from(mixed ...$payload): object
189191
{
192+
190193
$payloads = [];
191194
foreach ($payload as $field => $itemPayload) {
195+
$itemPayload = $this->normalizerCastResolver->resolve($itemPayload);
192196
$values = is_numeric($field) && is_array($itemPayload) ? $itemPayload : [$field => $itemPayload];
193197
$payloads = [...$payloads, ...$values];
194198
}

src/Support/Factories/ContextFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public static function build(string $className): SerializeContext
2828
propertyInputValueResolver: SerializeContainer::get()->propertyInputValueResolver(),
2929
propertyToArrayResolver: SerializeContainer::get()->propertyToArrayResolver(),
3030
fakerResolver: SerializeContainer::get()->fakerResolver(),
31+
normalizerCastResolver: SerializeContainer::get()->normalizerCastResolver(),
3132
));
3233
}
3334
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
use Astral\Serialize\Serialize;
4+
5+
beforeAll(function () {
6+
class NormalizerOne extends Serialize
7+
{
8+
public string $name_one;
9+
public int $id_one;
10+
}
11+
12+
class NormalizerTwo extends Serialize
13+
{
14+
public string $name_two;
15+
public int $id_two;
16+
}
17+
18+
class NormalizerClass extends Serialize
19+
{
20+
public NormalizerOne $one;
21+
public NormalizerTwo $two;
22+
23+
public mixed $three;
24+
}
25+
26+
});
27+
28+
it('test normalizer Serialize class', function () {
29+
30+
$normalizerOne = new NormalizerOne();
31+
$normalizerOne->name_one = 'one name';
32+
$normalizerOne->id_one = 1;
33+
34+
$normalizerTwo = new NormalizerTwo();
35+
$normalizerTwo->name_two = 'two name';
36+
$normalizerTwo->id_two = 2;
37+
38+
$res = NormalizerClass::from(one: $normalizerOne, two: $normalizerTwo, three: $normalizerOne);
39+
40+
expect($res->one)->toBeInstanceOf(NormalizerOne::class)
41+
->and($res->one->name_one)->toBe('one name')
42+
->and($res->one->id_one)->toBe(1)
43+
->and($res->two)->toBeInstanceOf(NormalizerTwo::class)
44+
->and($res->two->name_two)->toBe('two name')
45+
->and($res->two->id_two)->toBe(2)
46+
->and($res->three)->toBeArray()
47+
->and($res->three)->toMatchArray([
48+
'name_one' => 'one name',
49+
'id_one' => 1
50+
]);
51+
52+
$resJson = json_encode($res);
53+
expect($resJson)->toBe('{"code":200,"message":"\u64cd\u4f5c\u6210\u529f","data":{"one":{"code":200,"message":"\u64cd\u4f5c\u6210\u529f","data":{"name_one":"one name","id_one":1}},"two":{"code":200,"message":"\u64cd\u4f5c\u6210\u529f","data":{"name_two":"two name","id_two":2}},"three":{"name_one":"one name","id_one":1}}}');
54+
});
55+

0 commit comments

Comments
 (0)