Skip to content

Commit c02ea14

Browse files
authored
Merge pull request #33 from magicsunday/codex/verify-readme-examples-against-tests
docs: sync README and recipes with tests
2 parents 37dd6e9 + 6146c7d commit c02ea14

File tree

6 files changed

+42
-24
lines changed

6 files changed

+42
-24
lines changed

README.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ final class ArticleCollection extends ArrayObject
5151
final class Article
5252
{
5353
public string $title;
54+
55+
/**
56+
* @var CommentCollection<int, Comment>
57+
*/
5458
public CommentCollection $comments;
5559
}
5660
```
@@ -60,7 +64,7 @@ require __DIR__ . '/vendor/autoload.php';
6064

6165
use App\Dto\Article;
6266
use App\Dto\ArticleCollection;
63-
use MagicSunday\JsonMapper\JsonMapper;
67+
use MagicSunday\JsonMapper;
6468
use Symfony\Component\PropertyAccess\PropertyAccess;
6569
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
6670
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
@@ -89,6 +93,8 @@ var_dump($article, $articles);
8993

9094
The first call produces an `Article` instance with a populated `CommentCollection`; the second call returns an `ArticleCollection` containing `Article` objects.
9195

96+
Test coverage: `tests/JsonMapper/DocsQuickStartTest.php`.
97+
9298
### PHP classes
9399
In order to guarantee a seamless mapping of a JSON response into PHP classes you should prepare your classes well.
94100
Annotate all properties with the requested type.
@@ -170,7 +176,7 @@ To use the `PhpDocExtractor` extractor you need to install the `phpdocumentor/re
170176
require __DIR__ . '/vendor/autoload.php';
171177

172178
use MagicSunday\JsonMapper\Converter\CamelCasePropertyNameConverter;
173-
use MagicSunday\JsonMapper\JsonMapper;
179+
use MagicSunday\JsonMapper;
174180
use Symfony\Component\PropertyAccess\PropertyAccess;
175181
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
176182
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
@@ -219,7 +225,7 @@ You may alternatively implement `\MagicSunday\JsonMapper\Value\TypeHandlerInterf
219225
require __DIR__ . '/vendor/autoload.php';
220226

221227
use DateTimeImmutable;
222-
use MagicSunday\JsonMapper\JsonMapper;
228+
use MagicSunday\JsonMapper;
223229
use MagicSunday\JsonMapper\Value\ClosureTypeHandler;
224230
use stdClass;
225231
use Symfony\Component\PropertyAccess\PropertyAccess;
@@ -294,7 +300,7 @@ and optional the name of a collection class to the method.
294300
require __DIR__ . '/vendor/autoload.php';
295301

296302
use ArrayObject;
297-
use MagicSunday\JsonMapper\JsonMapper;
303+
use MagicSunday\JsonMapper;
298304
use Symfony\Component\PropertyAccess\PropertyAccess;
299305
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
300306
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
@@ -333,7 +339,7 @@ A complete set-up may look like this:
333339
require __DIR__ . '/vendor/autoload.php';
334340

335341
use MagicSunday\JsonMapper\Converter\CamelCasePropertyNameConverter;
336-
use MagicSunday\JsonMapper\JsonMapper;
342+
use MagicSunday\JsonMapper;
337343
use Symfony\Component\PropertyAccess\PropertyAccess;
338344
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
339345
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
@@ -372,7 +378,7 @@ Use `JsonMapper::addCustomClassMapEntry()` when the target class depends on runt
372378
```php
373379
require __DIR__ . '/vendor/autoload.php';
374380

375-
use MagicSunday\JsonMapper\JsonMapper;
381+
use MagicSunday\JsonMapper;
376382
use Symfony\Component\PropertyAccess\PropertyAccess;
377383
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
378384
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
@@ -413,7 +419,7 @@ The mapper operates in a lenient mode by default. Switch to strict mapping when
413419
require __DIR__ . '/vendor/autoload.php';
414420

415421
use MagicSunday\JsonMapper\Configuration\JsonMapperConfiguration;
416-
use MagicSunday\JsonMapper\JsonMapper;
422+
use MagicSunday\JsonMapper;
417423
use Symfony\Component\PropertyAccess\PropertyAccess;
418424
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
419425
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
@@ -453,7 +459,7 @@ Type resolution is the most expensive part of a mapping run. Provide a PSR-6 cac
453459
```php
454460
require __DIR__ . '/vendor/autoload.php';
455461

456-
use MagicSunday\JsonMapper\JsonMapper;
462+
use MagicSunday\JsonMapper;
457463
use Symfony\Component\Cache\Adapter\ArrayAdapter;
458464
use Symfony\Component\PropertyAccess\PropertyAccess;
459465
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;

docs/API.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ The `JsonMapper` class is the main entry point for mapping arbitrary JSON struct
1010
<?php
1111
declare(strict_types=1);
1212

13-
use MagicSunday\JsonMapper\JsonMapper;
13+
use MagicSunday\JsonMapper;
1414
use Symfony\Component\Cache\Adapter\ArrayAdapter;
1515
use Symfony\Component\PropertyAccess\PropertyAccess;
1616
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
@@ -82,7 +82,7 @@ declare(strict_types=1);
8282
require __DIR__ . '/vendor/autoload.php';
8383

8484
use MagicSunday\JsonMapper\Converter\CamelCasePropertyNameConverter;
85-
use MagicSunday\JsonMapper\JsonMapper;
85+
use MagicSunday\JsonMapper;
8686
use Symfony\Component\PropertyAccess\PropertyAccess;
8787
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
8888
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;

docs/recipes/custom-name-converter.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,23 @@ declare(strict_types=1);
2727
require __DIR__ . '/vendor/autoload.php';
2828

2929
use App\Converter\UpperSnakeCaseConverter;
30-
use MagicSunday\JsonMapper\Converter\CamelCasePropertyNameConverter;
31-
use MagicSunday\JsonMapper\JsonMapper;
30+
use MagicSunday\JsonMapper;
3231
use Symfony\Component\PropertyAccess\PropertyAccess;
3332
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
3433
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
3534
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
3635

37-
// Collect metadata and choose the converter implementation.
36+
// Collect metadata and provide the custom converter.
3837
$propertyInfo = new PropertyInfoExtractor(
3938
listExtractors: [new ReflectionExtractor()],
4039
typeExtractors: [new PhpDocExtractor()],
4140
);
4241
$propertyAccessor = PropertyAccess::createPropertyAccessor();
43-
$converter = new CamelCasePropertyNameConverter();
44-
// or $converter = new UpperSnakeCaseConverter();
42+
$converter = new UpperSnakeCaseConverter();
4543

4644
$mapper = new JsonMapper($propertyInfo, $propertyAccessor, $converter);
4745
```
4846

4947
Name converters are stateless and should be declared `final`. They are applied to every property access during mapping, so keep the implementation idempotent and efficient.
48+
49+
Test coverage: `tests/JsonMapper/DocsCustomNameConverterTest.php`.

docs/recipes/mapping-with-enums.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ require __DIR__ . '/vendor/autoload.php';
2929

3030
use App\Dto\Article;
3131
use App\Dto\Status;
32-
use MagicSunday\JsonMapper\Configuration\JsonMapperConfiguration;
33-
use MagicSunday\JsonMapper\JsonMapper;
32+
use MagicSunday\JsonMapper;
3433
use Symfony\Component\PropertyAccess\PropertyAccess;
3534
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
3635
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
@@ -48,12 +47,14 @@ $propertyInfo = new PropertyInfoExtractor(
4847
typeExtractors: [new PhpDocExtractor()],
4948
);
5049
$propertyAccessor = PropertyAccess::createPropertyAccessor();
51-
$configuration = JsonMapperConfiguration::lenient();
5250

5351
$mapper = new JsonMapper($propertyInfo, $propertyAccessor);
54-
$article = $mapper->map($json, Article::class, configuration: $configuration);
52+
$article = $mapper->map($json, Article::class);
5553

5654
assert($article instanceof Article);
5755
assert($article->status === Status::Published);
5856
```
59-
The mapper validates enum values. When strict mode is enabled (`JsonMapperConfiguration::strict()`), an invalid enum value results in a `TypeMismatchException`.
57+
58+
The mapper validates enum values. In strict mode (`JsonMapperConfiguration::strict()`), an invalid enum value results in a `TypeMismatchException` instead of populating the property.
59+
60+
Test coverage: `tests/JsonMapperTest.php::mapBackedEnumFromString` and `tests/JsonMapper/JsonMapperErrorHandlingTest.php::itReportsInvalidEnumValuesInLenientMode`.

docs/recipes/nested-collections.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use App\Dto\Article;
5353
use App\Dto\ArticleCollection;
5454
use App\Dto\NestedTagCollection;
5555
use App\Dto\TagCollection;
56-
use MagicSunday\JsonMapper\JsonMapper;
56+
use MagicSunday\JsonMapper;
5757
use Symfony\Component\PropertyAccess\PropertyAccess;
5858
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
5959
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
@@ -87,3 +87,6 @@ assert($articles[0]->tags instanceof NestedTagCollection);
8787
```
8888

8989
Each custom collection advertises its value type through the `@extends` PHPDoc annotation, allowing the mapper to recurse through nested structures.
90+
91+
Test coverage: `tests/JsonMapper/DocsNestedCollectionsTest.php`.
92+

docs/recipes/using-attributes.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,17 @@ use MagicSunday\JsonMapper\Attribute\ReplaceNullWithDefaultValue;
1515

1616
final class User
1717
{
18+
/**
19+
* @var list<string>
20+
*/
1821
#[ReplaceNullWithDefaultValue]
1922
public array $roles = [];
2023
}
2124
```
2225

23-
When a payload contains `{ "roles": null }`, the mapper keeps the default empty array.
26+
When a payload contains `{ "roles": null }`, the mapper keeps the default empty array instead of overwriting it with `null`.
27+
28+
Test coverage: `tests/JsonMapperTest.php::mapNullToDefaultValueUsingAttribute`.
2429

2530
## `ReplaceProperty`
2631
Apply this attribute at class level to redirect one or more incoming property names to a different target property.
@@ -33,13 +38,16 @@ namespace App\Dto;
3338

3439
use MagicSunday\JsonMapper\Attribute\ReplaceProperty;
3540

36-
#[ReplaceProperty('fullName', replaces: ['first_name', 'name'])]
41+
#[ReplaceProperty('fullName', replaces: 'first_name')]
42+
#[ReplaceProperty('fullName', replaces: 'name')]
3743
final class Contact
3844
{
3945
public string $fullName;
4046
}
4147
```
4248

43-
Both `first_name` and `name` keys will populate the `$fullName` property. Order matters: the first matching alias wins.
49+
Both `first_name` and `name` keys populate the `$fullName` property. Declare one attribute per alias to express the precedence order explicitly.
50+
51+
Test coverage: `tests/Attribute/ReplacePropertyTest.php::replaceProperty`.
4452

4553
Attributes can be combined with PHPDoc annotations and work alongside the classic DocBlock metadata.

0 commit comments

Comments
 (0)