Skip to content

Commit 1e2997e

Browse files
committed
Minor update
1 parent 118cc40 commit 1e2997e

File tree

2 files changed

+98
-45
lines changed

2 files changed

+98
-45
lines changed

CHANGELOG.md

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +0,0 @@
1-
## Unreleased
2-
3-
### Added
4-
- Introduced `JsonMapper::createWithDefaults()` to bootstrap the mapper with Symfony reflection, PhpDoc extractors, and a default property accessor.
5-
6-
### Changed
7-
- Marked `MagicSunday\\JsonMapper\\JsonMapper` as `final` and promoted constructor dependencies to `readonly` properties for consistent visibility.
8-
- Declared `MagicSunday\\JsonMapper\\Converter\\CamelCasePropertyNameConverter` as `final` and immutable.
9-
10-
### Documentation
11-
- Added a quick start walkthrough and guidance on type converters, error strategies, and performance tuning to the README.
12-
- Published an API reference (`docs/API.md`) and new recipe guides for enums, attributes, nested collections, and custom name converters.

src/JsonMapper.php

Lines changed: 98 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,13 @@ function (string $className, ?array $arguments): object {
157157
function (mixed $value, string $resolvedClass, MappingContext $context): mixed {
158158
$configuration = JsonMapperConfiguration::fromContext($context);
159159

160-
return $this->map($value, $resolvedClass, null, $context, $configuration);
160+
return $this->map(
161+
$value,
162+
$resolvedClass,
163+
null,
164+
$context,
165+
$configuration
166+
);
161167
},
162168
),
163169
);
@@ -280,7 +286,10 @@ public function map(
280286

281287
$this->assertClassesExists($resolvedClassName, $resolvedCollectionClassName);
282288

283-
$collectionValueType = $this->extractCollectionType($resolvedClassName, $resolvedCollectionClassName);
289+
$collectionValueType = $this->extractCollectionType(
290+
$resolvedClassName,
291+
$resolvedCollectionClassName
292+
);
284293

285294
$collectionResult = $this->mapCollection(
286295
$json,
@@ -323,7 +332,14 @@ public function mapWithReport(
323332
): MappingResult {
324333
$configuration = ($configuration ?? $this->createDefaultConfiguration())->withErrorCollection(true);
325334
$context = new MappingContext($json, $configuration->toOptions());
326-
$value = $this->map($json, $className, $collectionClassName, $context, $configuration);
335+
336+
$value = $this->map(
337+
$json,
338+
$className,
339+
$collectionClassName,
340+
$context,
341+
$configuration
342+
);
327343

328344
return new MappingResult($value, new MappingReport($context->getErrorRecords()));
329345
}
@@ -351,20 +367,24 @@ private function extractCollectionType(
351367
$docBlockCollectionType = $this->collectionDocBlockTypeResolver->resolve($resolvedCollectionClassName);
352368

353369
if (!$docBlockCollectionType instanceof CollectionType) {
354-
throw new InvalidArgumentException(sprintf(
355-
'Unable to resolve the element type for collection [%s]. Define an "@extends" annotation such as "@extends %s<YourClass>".',
356-
$resolvedCollectionClassName,
357-
$resolvedCollectionClassName,
358-
));
370+
throw new InvalidArgumentException(
371+
sprintf(
372+
'Unable to resolve the element type for collection [%s]. Define an "@extends" annotation such as "@extends %s<YourClass>".',
373+
$resolvedCollectionClassName,
374+
$resolvedCollectionClassName,
375+
)
376+
);
359377
}
360378

361379
$collectionValueType = $docBlockCollectionType->getCollectionValueType();
362380

363381
if ($collectionValueType instanceof TemplateType) {
364-
throw new InvalidArgumentException(sprintf(
365-
'Unable to resolve the element type for collection [%s]. Please provide a concrete class in the "@extends" annotation.',
366-
$resolvedCollectionClassName,
367-
));
382+
throw new InvalidArgumentException(
383+
sprintf(
384+
'Unable to resolve the element type for collection [%s]. Please provide a concrete class in the "@extends" annotation.',
385+
$resolvedCollectionClassName,
386+
)
387+
);
368388
}
369389

370390
return $collectionValueType;
@@ -392,7 +412,9 @@ private function mapCollection(
392412

393413
if ($isGenericCollectionMapping) {
394414
if ($resolvedCollectionClassName === null) {
395-
throw new InvalidArgumentException('A collection class name must be provided when mapping without an element class.');
415+
throw new InvalidArgumentException(
416+
'A collection class name must be provided when mapping without an element class.'
417+
);
396418
}
397419

398420
$collection = $this->collectionFactory->mapIterable($json, $collectionValueType, $context);
@@ -576,8 +598,11 @@ private function createDefaultConfiguration(): JsonMapperConfiguration
576598
*
577599
* @return list<string> List of property names that are still required after mapping.
578600
*/
579-
private function determineMissingProperties(string $className, array $declaredProperties, array $mappedProperties): array
580-
{
601+
private function determineMissingProperties(
602+
string $className,
603+
array $declaredProperties,
604+
array $mappedProperties,
605+
): array {
581606
$used = array_values(array_unique($mappedProperties));
582607

583608
return array_values(array_filter(
@@ -632,8 +657,11 @@ private function isRequiredProperty(string $className, string $propertyName): bo
632657
* @param MappingContext $context Context collecting the error information.
633658
* @param JsonMapperConfiguration $configuration Configuration that controls strict-mode behaviour.
634659
*/
635-
private function handleMappingException(MappingException $exception, MappingContext $context, JsonMapperConfiguration $configuration): void
636-
{
660+
private function handleMappingException(
661+
MappingException $exception,
662+
MappingContext $context,
663+
JsonMapperConfiguration $configuration,
664+
): void {
637665
$context->recordException($exception);
638666

639667
// Strict mode propagates the failure immediately to abort mapping on the first error.
@@ -645,8 +673,11 @@ private function handleMappingException(MappingException $exception, MappingCont
645673
/**
646674
* Converts the provided JSON value using the registered strategies.
647675
*/
648-
private function convertValue(mixed $json, Type $type, MappingContext $context): mixed
649-
{
676+
private function convertValue(
677+
mixed $json,
678+
Type $type,
679+
MappingContext $context,
680+
): mixed {
650681
if (
651682
is_string($json)
652683
&& ($json === '' || trim($json) === '')
@@ -679,8 +710,11 @@ private function convertValue(mixed $json, Type $type, MappingContext $context):
679710
*
680711
* @return mixed Value converted to a type accepted by the union.
681712
*/
682-
private function convertUnionValue(mixed $json, UnionType $type, MappingContext $context): mixed
683-
{
713+
private function convertUnionValue(
714+
mixed $json,
715+
UnionType $type,
716+
MappingContext $context,
717+
): mixed {
684718
if ($json === null && $this->unionAllowsNull($type)) {
685719
return null;
686720
}
@@ -810,7 +844,7 @@ private function unionAllowsNull(UnionType $type): bool
810844
*/
811845
private function isNullType(Type $type): bool
812846
{
813-
return $type instanceof BuiltinType && $type->getTypeIdentifier() === TypeIdentifier::NULL;
847+
return ($type instanceof BuiltinType) && ($type->getTypeIdentifier() === TypeIdentifier::NULL);
814848
}
815849

816850
/**
@@ -860,9 +894,10 @@ private function buildReplacePropertyMap(string $className): array
860894
return [];
861895
}
862896

863-
$map = [];
897+
$map = [];
898+
$attributes = $reflectionClass->getAttributes(ReplaceProperty::class, ReflectionAttribute::IS_INSTANCEOF);
864899

865-
foreach ($reflectionClass->getAttributes(ReplaceProperty::class, ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
900+
foreach ($attributes as $attribute) {
866901
/** @var ReplaceProperty $instance */
867902
$instance = $attribute->newInstance();
868903
$map[$instance->replaces] = $instance->value;
@@ -896,11 +931,17 @@ private function normalizePropertyName(string|int $propertyName, array $replaceP
896931
{
897932
$normalized = $propertyName;
898933

899-
if (is_string($normalized) && array_key_exists($normalized, $replacePropertyMap)) {
934+
if (
935+
is_string($normalized)
936+
&& array_key_exists($normalized, $replacePropertyMap)
937+
) {
900938
$normalized = $replacePropertyMap[$normalized];
901939
}
902940

903-
if (is_string($normalized) && ($this->nameConverter instanceof PropertyNameConverterInterface)) {
941+
if (
942+
is_string($normalized)
943+
&& ($this->nameConverter instanceof PropertyNameConverterInterface)
944+
) {
904945
return $this->nameConverter->convert($normalized);
905946
}
906947

@@ -1002,7 +1043,10 @@ private function isNumericIndexArray(array|object $json): bool
10021043
*/
10031044
private function isIterableWithArraysOrObjects(mixed $json): bool
10041045
{
1005-
if (!is_array($json) && !is_object($json)) {
1046+
if (
1047+
!is_array($json)
1048+
&& !is_object($json)
1049+
) {
10061050
return false;
10071051
}
10081052

@@ -1028,8 +1072,16 @@ private function isIterableWithArraysOrObjects(mixed $json): bool
10281072
*/
10291073
private function assertClassesExists(?string $className, ?string $collectionClassName = null): void
10301074
{
1031-
if ($className !== null && !class_exists($className)) {
1032-
throw new InvalidArgumentException(sprintf('Class [%s] does not exist', $className));
1075+
if (
1076+
($className !== null)
1077+
&& !class_exists($className)
1078+
) {
1079+
throw new InvalidArgumentException(
1080+
sprintf(
1081+
'Class [%s] does not exist',
1082+
$className
1083+
)
1084+
);
10331085
}
10341086

10351087
if ($collectionClassName === null) {
@@ -1040,18 +1092,31 @@ private function assertClassesExists(?string $className, ?string $collectionClas
10401092
return;
10411093
}
10421094

1043-
throw new InvalidArgumentException(sprintf('Class [%s] does not exist', $collectionClassName));
1095+
throw new InvalidArgumentException(
1096+
sprintf(
1097+
'Class [%s] does not exist',
1098+
$collectionClassName
1099+
)
1100+
);
10441101
}
10451102

10461103
/**
10471104
* Sets a property value.
10481105
*/
1049-
private function setProperty(object $entity, string $name, mixed $value, MappingContext $context): void
1050-
{
1106+
private function setProperty(
1107+
object $entity,
1108+
string $name,
1109+
mixed $value,
1110+
MappingContext $context,
1111+
): void {
10511112
$reflectionProperty = $this->getReflectionProperty($entity::class, $name);
10521113

10531114
if ($reflectionProperty instanceof ReflectionProperty && $reflectionProperty->isReadOnly()) {
1054-
throw new ReadonlyPropertyException($context->getPath(), $name, $entity::class);
1115+
throw new ReadonlyPropertyException(
1116+
$context->getPath(),
1117+
$name,
1118+
$entity::class
1119+
);
10551120
}
10561121

10571122
if (is_array($value)) {

0 commit comments

Comments
 (0)