Skip to content

Commit 64e93eb

Browse files
committed
docs(serialization): serialization support for Laravel Eloquent & fix image
1 parent 31bc652 commit 64e93eb

File tree

1 file changed

+82
-14
lines changed

1 file changed

+82
-14
lines changed

core/serialization.md

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,24 @@
22

33
## Overall Process
44

5-
API Platform embraces and extends the Symfony Serializer Component to transform PHP entities in (hypermedia) API responses.
5+
API Platform embraces and extends the Symfony Serializer Component & Eloquent Serialization to transform PHP entities in
6+
(hypermedia) API responses.
67

78
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/serializer?cid=apip"><img src="../symfony/images/symfonycasts-player.png" alt="Serializer screencast"><br>Watch the Serializer screencast</a></p>
89

910
The main serialization process has two stages:
1011

11-
![Serializer workflow](/docs/core/images/SerializerWorkflow.png)
12+
![Serializer workflow](/core/images/SerializerWorkflow.png)
1213

1314
> As you can see in the picture above, an array is used as a man-in-the-middle. This way, Encoders will only deal with turning specific formats into arrays and vice versa. The same way, Normalizers will deal with turning specific objects into arrays and vice versa.
1415
> -- [The Symfony documentation](https://symfony.com/doc/current/components/serializer.html)
1516
16-
Unlike Symfony itself, API Platform leverages custom normalizers, its router and the [state provider](state-providers.md) system to perform an advanced transformation. Metadata are added to the generated document including links, type information, pagination data or available filters.
17+
Unlike Symfony or Laravel themselves, API Platform leverages custom normalizers, its router and the [state provider](state-providers.md)
18+
system to perform an advanced transformation. Metadata are added to the generated document including links, type
19+
information, pagination data or available filters.
1720

18-
The API Platform Serializer is extendable. You can register custom normalizers and encoders in order to support other formats. You can also decorate existing normalizers to customize their behaviors.
21+
The API Platform Serializer is extendable. You can register custom normalizers and encoders in order to support other formats.
22+
You can also decorate existing normalizers to customize their behaviors.
1923

2024
## Available Serializers
2125

@@ -27,7 +31,7 @@ JSON-LD, or JavaScript Object Notation for Linked Data, is a method of encoding
2731
- [HAL](https://en.wikipedia.org/wiki/Hypertext_Application_Language) serializer
2832
`api_platform.hal.normalizer.item`
2933

30-
- JSON, XML, CSV, YAML serializer (using the Symfony serializer)
34+
- JSON, XML, CSV, YAML serializer (using the Symfony serializer or the Eloquent Serialization)
3135
`api_platform.serializer.normalizer.item`
3236

3337
## The Serialization Context, Groups and Relations
@@ -41,7 +45,7 @@ feature of the Symfony Serializer component.
4145
In addition to groups, you can use any option supported by the Symfony Serializer. For example, you can use [`enable_max_depth`](https://symfony.com/doc/current/components/serializer.html#handling-serialization-depth)
4246
to limit the serialization depth.
4347

44-
### Configuration
48+
### Configuration for Symfony
4549

4650
Just like other Symfony and API Platform components, the Serializer component can be configured using attributes, XML
4751
or YAML. Since attributes are easy to understand, we will use them in the following examples.
@@ -69,6 +73,9 @@ framework:
6973

7074
## Using Serialization Groups
7175

76+
> [!NOTE]
77+
> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”.
78+
7279
It is simple to specify what groups to use in the API system:
7380

7481
1. Add the normalization context and denormalization context attributes to the resource, and specify which groups to use. Here you see that we add `read` and `write`, respectively. You can use any group names you wish.
@@ -101,6 +108,7 @@ class Book
101108
```
102109

103110
```yaml
111+
# The YAML syntax is only supported for Symfony
104112
# api/config/api_platform/resources.yaml
105113
resources:
106114
App\Entity\Book:
@@ -109,6 +117,7 @@ resources:
109117
denormalizationContext:
110118
groups: ['write']
111119
120+
# The YAML syntax is only supported for Symfony
112121
# api/config/serialization/Book.yaml
113122
App\Entity\Book:
114123
attributes:
@@ -119,6 +128,7 @@ App\Entity\Book:
119128
```
120129

121130
```xml
131+
<!--The XML syntax is only supported for Symfony -->
122132
<!-- api/config/api_platform/resources.xml -->
123133
<?xml version="1.0" encoding="UTF-8" ?>
124134
<resources xmlns="https://api-platform.com/schema/metadata/resources-3.0"
@@ -146,7 +156,8 @@ App\Entity\Book:
146156
</denormalizationContext>
147157
</resource>
148158
</resources>
149-
159+
160+
<!--The XML syntax is only supported for Symfony -->
150161
<!-- api/config/serialization/Book.xml -->
151162
<?xml version="1.0" encoding="UTF-8" ?>
152163
<serializer xmlns="http://symfony.com/schema/dic/serializer-mapping"
@@ -184,6 +195,15 @@ documentation generator.
184195

185196
## Using Serialization Groups per Operation
186197

198+
> [!NOTE]
199+
> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”.
200+
201+
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform/relations?cid=apip"><img src="../symfony/images/symfonycasts-player.png" alt="Relations screencast"><br>Watch the Relations screencast</a></p>
202+
203+
By default, the serializer provided with API Platform represents relations between objects using [dereferenceable IRIs](https://en.wikipedia.org/wiki/Internationalized_Resource_Identifier).
204+
They allow you to retrieve details for related objects by issuing extra HTTP requests. However, for performance reasons, it is sometimes preferable to avoid forcing the client to issue extra HTTP requests.
205+
206+
187207
It is possible to specify normalization and denormalization contexts (as well as any other attribute) on a per-operation
188208
basis. API Platform will always use the most specific definition. For instance, if normalization groups are set both
189209
at the resource level and at the operation level, the configuration set at the operation level will be used and the resource
@@ -219,6 +239,7 @@ class Book
219239
```
220240

221241
```yaml
242+
# The YAML syntax is only supported for Symfony
222243
# api/config/api_platform/resources/Book.yaml
223244
App\Entity\Book:
224245
normalizationContext:
@@ -229,6 +250,7 @@ App\Entity\Book:
229250
normalizationContext:
230251
groups: ['patch']
231252
253+
# The YAML syntax is only supported for Symfony
232254
# api/config/serializer/Book.yaml
233255
App\Entity\Book:
234256
attributes:
@@ -239,6 +261,7 @@ App\Entity\Book:
239261
```
240262

241263
```xml
264+
<!-- The XML syntax is only supported for Symfony -->
242265
<!-- api/config/api_platform/resources.xml -->
243266
<?xml version="1.0" encoding="UTF-8" ?>
244267
<resources xmlns="https://api-platform.com/schema/metadata/resources-3.0"
@@ -272,6 +295,7 @@ App\Entity\Book:
272295
</resource>
273296
</resources>
274297
298+
<!-- The XML syntax is only supported for Symfony -->
275299
<!-- api/config/serialization/Book.xml -->
276300
<?xml version="1.0" encoding="UTF-8" ?>
277301
<serializer xmlns="http://symfony.com/schema/dic/serializer-mapping"
@@ -309,6 +333,9 @@ They allow you to retrieve details for related objects by issuing extra HTTP req
309333

310334
### Normalization
311335

336+
> [!NOTE]
337+
> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”.
338+
312339
In the following JSON document, the relation from a book to an author is by default represented by an URI:
313340

314341
```json
@@ -350,11 +377,13 @@ class Book
350377
```
351378

352379
```yaml
380+
# The YAML syntax is only supported for Symfony
353381
# api/config/api_platform/resources/Book.yaml
354382
App\Entity\Book:
355383
normalizationContext:
356384
groups: ['book']
357385
386+
# The YAML syntax is only supported for Symfony
358387
# api/config/serializer/Book.yaml
359388
App\Entity\Book:
360389
attributes:
@@ -387,6 +416,7 @@ class Person
387416
```
388417

389418
```yaml
419+
# The YAML syntax is only supported for Symfony
390420
# api/config/serializer/Person.yaml
391421
App\Entity\Person:
392422
attributes:
@@ -420,6 +450,9 @@ Instead of embedding relations in the main HTTP response, you may want [to "push
420450

421451
### Denormalization
422452

453+
> [!NOTE]
454+
> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”.
455+
423456
It is also possible to embed a relation in `PUT`, `PATCH` and `POST` requests. To enable that feature, set the serialization groups
424457
the same way as normalization. For example:
425458

@@ -440,6 +473,7 @@ class Book
440473
```
441474

442475
```yaml
476+
# The YAML syntax is only supported for Symfony
443477
# api/config/api_platform/resources/Book.yaml
444478
App\Entity\Book:
445479
denormalizationContext:
@@ -458,6 +492,9 @@ You can specify as many embedded relation levels as you want.
458492

459493
### Force IRI with relations of the same type (parent/childs relations)
460494

495+
> [!NOTE]
496+
> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”.
497+
461498
It is a common problem to have entities that reference other entities of the same type:
462499

463500
<code-selector>
@@ -490,13 +527,15 @@ class Person
490527
```
491528

492529
```yaml
530+
# The YAML syntax is only supported for Symfony
493531
# api/config/api_platform/resources/Person.yaml
494532
App\Entity\Person:
495533
normalizationContext:
496534
groups: ['person']
497535
denormalizationContext:
498536
groups: ['person']
499537
538+
# The YAML syntax is only supported for Symfony
500539
# api/config/serializer/Person.yaml
501540
App\Entity\Person:
502541
attributes:
@@ -542,6 +581,7 @@ class Person
542581
```
543582

544583
```yaml
584+
# The YAML syntax is only supported for Symfony
545585
# api/config/api_platform/resources/Person.yaml
546586
resources:
547587
App\Entity\Person:
@@ -555,6 +595,7 @@ properties:
555595
readableLink: false
556596
writableLink: false
557597
598+
# The YAML syntax is only supported for Symfony
558599
# api/config/serializer/Person.yaml
559600
App\Entity\Person:
560601
attributes:
@@ -566,7 +607,7 @@ App\Entity\Person:
566607

567608
</code-selector>
568609

569-
### Plain Identifiers
610+
### Plain Identifiers for Symfony
570611

571612
Instead of sending an IRI to set a relation, you may want to send a plain identifier. To do so, you must create your own denormalizer:
572613

@@ -617,7 +658,7 @@ class PlainIdentifierDenormalizer implements DenormalizerInterface, Denormalizer
617658
}
618659
```
619660

620-
## Property Normalization Context
661+
## Property Normalization Context for Symfony
621662

622663
If you want to change the (de)normalization context of a property, for instance if you want to change the format of the date time,
623664
you can do so by using the `#[Context]` attribute from the Symfony Serializer component.
@@ -710,6 +751,9 @@ class Book
710751

711752
## Calculated Field
712753

754+
> [!NOTE]
755+
> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”.
756+
713757
Sometimes you need to expose calculated fields. This can be done by leveraging the groups. This time not on a property, but on a method.
714758

715759
<code-selector>
@@ -755,13 +799,15 @@ class Greeting
755799
```
756800

757801
```yaml
802+
# The YAML syntax is only supported for Symfony
758803
# api/config/api_platform/resources/Greeting.yaml
759804
App\Entity\Greeting:
760805
operations:
761806
ApiPlatform\Metadata\GetCollection:
762807
normalizationContext:
763808
groups: 'greeting:collection:get'
764809
810+
# The YAML syntax is only supported for Symfony
765811
# api/config/serializer/Greeting.yaml
766812
App\Entity\Greeting:
767813
attributes:
@@ -777,6 +823,9 @@ App\Entity\Greeting:
777823

778824
## Changing the Serialization Context Dynamically
779825

826+
> [!NOTE]
827+
> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”.
828+
780829
<p align="center" class="symfonycasts"><a href="https://symfonycasts.com/screencast/api-platform-security/service-decoration?cid=apip"><img src="../symfony/images/symfonycasts-player.png" alt="Context Builder & Service Decoration screencast"><br>Watch the Context Builder & Service Decoration screencast</a></p>
781830

782831
Let's imagine a resource where most fields can be managed by any user, but some can be managed only by admin users:
@@ -816,13 +865,15 @@ class Book
816865
```
817866

818867
```yaml
868+
# The YAML syntax is only supported for Symfony
819869
# api/config/api_platform/resources/Book.yaml
820870
App\Entity\Book:
821871
normalizationContext:
822872
groups: ['book:output']
823873
denormalizationContext:
824874
groups: ['book:input']
825875
876+
# The YAML syntax is only supported for Symfony
826877
# api/config/serializer/Book.yaml
827878
App\Entity\Book:
828879
attributes:
@@ -842,6 +893,7 @@ API Platform implements a `ContextBuilder`, which prepares the context for seria
842893
`createFromRequest` method:
843894

844895
```yaml
896+
# The YAML syntax is only supported for Symfony
845897
# api/config/services.yaml
846898
services:
847899
# ...
@@ -890,7 +942,7 @@ If the user has the `ROLE_ADMIN` permission and the subject is an instance of Bo
890942
denormalization context. The `$normalization` variable lets you check whether the context is for normalization (if `TRUE`) or denormalization
891943
(`FALSE`).
892944

893-
## Changing the Serialization Context on a Per-item Basis
945+
## Changing the Serialization Context on a Per-item Basis for Symfony
894946

895947
The example above demonstrates how you can modify the normalization/denormalization context based on the current user
896948
permissions for all books. Sometimes, however, the permissions vary depending on what book is being processed.
@@ -973,7 +1025,7 @@ instance.
9731025
Note: In this example, we use the `TokenStorageInterface` to verify access to the book instance. However, Symfony
9741026
provides many useful other services that might be better suited to your use case. For example, the [`AuthorizationChecker`](https://symfony.com/doc/current/components/security/authorization.html#authorization-checker).
9751027

976-
## Name Conversion
1028+
## Name Conversion for Symfony
9771029

9781030
The Serializer Component provides a handy way to map PHP field names to serialized names. See the related [Symfony documentation](https://symfony.com/doc/current/components/serializer.html#converting-property-names-when-serializing-and-deserializing).
9791031

@@ -994,7 +1046,7 @@ api_platform:
9941046

9951047
If symfony's `MetadataAwareNameConverter` is available it'll be used by default. If you specify one in ApiPlatform configuration, it'll be used. Note that you can use decoration to benefit from this name converter in your own implementation.
9961048

997-
## Decorating a Serializer and Adding Extra Data
1049+
## Decorating a Serializer and Adding Extra Data for Symfony
9981050

9991051
In the following example, we will see how we add extra information to the serialized output. Here is how we add the
10001052
date on each request in `GET`:
@@ -1076,8 +1128,15 @@ final class ApiNormalizer implements NormalizerInterface, DenormalizerInterface,
10761128

10771129
## Entity Identifier Case
10781130

1079-
API Platform is able to guess the entity identifier using Doctrine metadata ([ORM](https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/basic-mapping.html#identifiers-primary-keys), [MongoDB ODM](https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/basic-mapping.html#identifiers)).
1080-
For ORM, it also supports [composite identifiers](https://www.doctrine-project.org/projects/doctrine-orm/en/current/tutorials/composite-primary-keys.html).
1131+
> [!NOTE]
1132+
> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”.
1133+
1134+
API Platform is able to guess the entity identifier using Doctrine metadata ([ORM](https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/basic-mapping.html#identifiers-primary-keys),
1135+
[MongoDB ODM](https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/basic-mapping.html#identifiers))
1136+
or Laravel Eloquent metadata ([ORM](https://laravel.com/docs/eloquent#primary-keys)).
1137+
1138+
For ORM, it also supports [Doctrine composite identifiers](https://www.doctrine-project.org/projects/doctrine-orm/en/current/tutorials/composite-primary-keys.html)
1139+
& [Eloquent composite identifiers](https://laravel.com/docs/eloquent#composite-primary-keys).
10811140

10821141
If you are not using the Doctrine ORM or MongoDB ODM Provider, you must explicitly mark the identifier using the `identifier` attribute of
10831142
the `ApiPlatform\Metadata\ApiProperty` annotation. For example:
@@ -1115,6 +1174,7 @@ class Book
11151174
```
11161175

11171176
```yaml
1177+
# The YAML syntax is only supported for Symfony
11181178
# api/config/api_platform/properties.yaml
11191179
properties:
11201180
App\Entity\Book:
@@ -1124,6 +1184,7 @@ properties:
11241184

11251185
```xml
11261186
<?xml version="1.0" encoding="UTF-8" ?>
1187+
<!-- The XML syntax is only supported for Symfony -->
11271188
<!-- api/config/api_platform/properties.xml -->
11281189
11291190
<properties xmlns="https://api-platform.com/schema/metadata/properties-3.0"
@@ -1147,6 +1208,9 @@ must do the following:
11471208

11481209
## Embedding the JSON-LD Context
11491210

1211+
> [!NOTE]
1212+
> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”.
1213+
11501214
By default, the generated [JSON-LD context](https://www.w3.org/TR/json-ld/#the-context) (`@context`) is only referenced by
11511215
an IRI. A client that uses JSON-LD must send a second HTTP request to retrieve it:
11521216

@@ -1180,6 +1244,7 @@ class Book
11801244
```
11811245

11821246
```yaml
1247+
# The YAML syntax is only supported for Symfony
11831248
# api/config/api_platform/resources/Book.yaml
11841249
App\Entity\Book:
11851250
normalizationContext:
@@ -1207,6 +1272,9 @@ The JSON output will now include the embedded context:
12071272

12081273
## Collection Relation
12091274

1275+
> [!NOTE]
1276+
> In Symfony we use the term “entities”, while the following documentation is mostly for Laravel “models”.
1277+
12101278
This is a special case where, in an entity, you have a `toMany` relation. By default, Doctrine will use an `ArrayCollection` to store your values. This is fine when you have a _read_ operation, but when you try to _write_ you can observe an issue where the response is not reflecting the changes correctly. It can lead to client errors even though the update was correct.
12111279
Indeed, after an update on this relation, the collection looks wrong because `ArrayCollection`'s indices are not sequential. To change this, we recommend to use a getter that returns `$collectionRelation->getValues()`. Thanks to this, the relation is now a real array which is sequentially indexed.
12121280

0 commit comments

Comments
 (0)