Skip to content

Commit 2df20c2

Browse files
committed
Add docs for data persisters
1 parent 0734d66 commit 2df20c2

File tree

4 files changed

+87
-16
lines changed

4 files changed

+87
-16
lines changed

core/data-persisters.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Data Persisters
2+
3+
To mutate the application states during `POST`, `PUT`, `PATCH` or `DELETE` [operations](operations.md), API Platform uses
4+
classes called **data persisters**. Data persisters receive an instance of the class marked as an API resource (usually using
5+
the `@ApiResource` annotation). This instance contains data submitted by the client during [the deserialization
6+
process](serialization.md).
7+
8+
A data persister using [Doctrine ORM](http://www.doctrine-project.org/projects/orm.html) is included with the library and
9+
is enabled by default. It is able to persist and delete objects that are also mapped as [Doctrine entities](https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/basic-mapping.html).
10+
11+
However, you may want to:
12+
13+
* store data to other persistence layers (ElasticSearch, MongoDB, external web services...)
14+
* not publicly expose the internal model mapped with the database through the API
15+
* use a separate model for [read operations](data-providers.md) and for updates by implementing patterns such as [CQRS](https://martinfowler.com/bliki/CQRS.html)
16+
17+
Custom data persisters can be used to do so. A project can include as many data persisters as it needs. The first able to
18+
persist data for a given resource will be used.
19+
20+
## Creating a Custom Data Persister
21+
22+
To create a data persister, you have to implement the [`DataPersisterInterface`](https://github.com/api-platform/core/blob/master/src/DataPersister/DataPersisterInterface.php).
23+
This interface defines only 3 methods:
24+
25+
* `persist`: to create or update the given data
26+
* `delete`: to delete the given data
27+
* `support`: to tell if the given data can be handled by this specific data persister
28+
29+
Here is an implementation example:
30+
31+
```php
32+
namespace App\DataPersister;
33+
34+
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
35+
use App\Entity\BlogPost;
36+
37+
final class BlogPostDataPersister implements DataPersisterInterface
38+
{
39+
public function supports($data): bool
40+
{
41+
return $data instanceof BlogPost;
42+
}
43+
44+
public function persist($data)
45+
{
46+
// call your persistence layer to save $data
47+
return $data;
48+
}
49+
50+
public function delete($data): void
51+
{
52+
// call your persistence layer to delete $data
53+
}
54+
}
55+
```
56+
57+
If service autowiring and autoconfiguration are enabled (it's the case by default), you are done!
58+
59+
Otherwise, if you use a custom dependency injection configuration, you need to register the corresponding service and add the
60+
`api_platform.data_persister` tag to it. The `priority` attribute can be used to order persisters.
61+
62+
```yaml
63+
# api/config/services.yaml
64+
services:
65+
# ...
66+
'App\DataPersister\BlogPostDataPersister': ~
67+
# Uncomment only if autoconfiguration is disabled
68+
#tags: [ 'api_platform.data_persister' ]
69+
```

core/data-providers.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ final class BlogPostCollectionDataProvider implements CollectionDataProviderInte
5858
}
5959
```
6060

61-
Then declare a Symfony service, for example:
61+
If you use the default configuration, the corresponding service will be automatically registered thanks to the [autowiring](https://symfony.com/doc/current/service_container/autowiring.html).
62+
To declare the service explicitly, or to set a custom priority, you can use the following snippet:
6263

6364
```yaml
6465
# api/config/services.yaml

core/events.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,10 @@ Built-in event listeners are:
7676
Name | Event | Pre & Post hooks | Priority | Description
7777
------------------------------|--------------------|--------------------------------------|----------|--------------------------------------------------------------------------------------------------------------------------
7878
`AddFormatListener` | `kernel.request` | None | 7 | guess the best response format ([content negotiation](content-negotiation.md))
79-
`ReadListener` | `kernel.request` | `PRE_READ`, `POST_READ` | 4 | retrieve data from the persistence system using the [data providers](data-providers.md)
79+
`ReadListener` | `kernel.request` | `PRE_READ`, `POST_READ` | 4 | retrieve data from the persistence system using the [data providers](data-providers.md) (`GET`, `PUT`, `DELETE`)
8080
`DeserializeListener` | `kernel.request` | `PRE_DESERIALIZE`, `POST_DESERIALIZE`| 2 | deserialize data into a PHP entity (`GET`, `POST`, `DELETE`); update the entity retrieved using the data provider (`PUT`)
8181
`ValidateListener` | `kernel.view` | `PRE_VALIDATE`, `POST_VALIDATE` | 64 | [validate data](validation.md) (`POST`, `PUT`)
82-
`WriteListener` | `kernel.view` | `PRE_WRITE`, `POST_WRITE` | 32 | if using the Doctrine ORM, persist data (`POST`, `PUT`, `DELETE`)
82+
`WriteListener` | `kernel.view` | `PRE_WRITE`, `POST_WRITE` | 32 | persist changes in the persistence system using the [data persisters](data-persisters.md) (`POST`, `PUT`, `DELETE`)
8383
`SerializeListener` | `kernel.view` | `PRE_SERIALIZE`, `POST_SERIALIZE` | 16 | serialize the PHP entity in string [according to the request format](content-negotiation.md)
8484
`RespondListener` | `kernel.view` | `PRE_RESPOND`, `POST_RESPOND` | 8 | transform serialized to a `Symfony\Component\HttpFoundation\Response` instance
8585
`AddLinkHeaderListener` | `kernel.response` | None | 0 | add a `Link` HTTP header pointing to the Hydra documentation

index.md

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,12 @@
8181
1. [Custom Collection Data Provider](core/data-providers.md#custom-collection-data-provider)
8282
2. [Custom Item Data Provider](core/data-providers.md#custom-item-data-provider)
8383
3. [Injecting the Serializer in an `ItemDataProvider`](core/data-providers.md#injecting-the-serializer-in-an-itemdataprovider)
84-
16. [Extensions](core/extensions.md)
84+
16. [Data Persisters](core/data-persisters.md)
85+
17. [Extensions](core/extensions.md)
8586
1. [Custom Extension](core/extensions.md#custom-extension)
8687
2. [Filter upon the current user](core/extensions.md#example)
87-
17. [Security](core/security.md)
88-
18. [Performance](core/performance.md)
88+
18. [Security](core/security.md)
89+
19. [Performance](core/performance.md)
8990
1. [Enabling the Built-in HTTP Cache Invalidation System](core/performance.md#enabling-the-builtin-http-cache-invalidation-system)
9091
2. [Enabling the Metadata Cache](core/performance.md#enabling-the-metadata-cache)
9192
3. [Using PPM (PHP-PM)](core/performance.md#using-ppm-php-pm)
@@ -97,32 +98,32 @@
9798
3. [Override at Resource and Operation Level](core/performance.md#override-at-resource-and-operation-level)
9899
4. [Disable Eager Loading](core/performance.md#disable-eager-loading)
99100
3. [Partial Pagination](core/performance.md#partial-pagination)
100-
19. [Operation Path Naming](core/operation-path-naming.md)
101+
20. [Operation Path Naming](core/operation-path-naming.md)
101102
1. [Configuration](core/operation-path-naming.md#configuration)
102103
2. [Create a Custom Operation Path Naming](core/operation-path-naming.md#create-a-custom-operation-path-resolver)
103104
1. [Defining the Operation Path Naming](core/operation-path-naming.md#defining-the-operation-path-resolver)
104105
2. [Registering the Service](core/operation-path-naming.md#registering-the-service)
105106
3. [Configure it](core/operation-path-naming.md#configure-it)
106-
20. [Accept application/x-www-form-urlencoded Form Data](core/form-data.md)
107-
21. [FOSUserBundle Integration](core/fosuser-bundle.md)
107+
21. [Accept application/x-www-form-urlencoded Form Data](core/form-data.md)
108+
22. [FOSUserBundle Integration](core/fosuser-bundle.md)
108109
1. [Installing the Bundle](core/fosuser-bundle.md#installing-the-bundle)
109110
2. [Enabling the Bridge](core/fosuser-bundle.md#enabling-the-bridge)
110111
3. [Creating a `User` Entity with Serialization Groups](core/fosuser-bundle.md#creating-a-user-entity-with-serialization-groups)
111-
22. [Adding a JWT authentication using LexikJWTAuthenticationBundle](core/jwt.md)
112+
23. [Adding a JWT authentication using LexikJWTAuthenticationBundle](core/jwt.md)
112113
1. [Testing with Swagger](core/jwt.md#testing-with-swagger)
113114
2. [Testing with Behat](core/jwt.md#testing-with-behat)
114-
23. [NelmioApiDocBundle integration](core/nelmio-api-doc.md)
115-
24. [AngularJS Integration](core/angularjs-integration.md)
115+
24. [NelmioApiDocBundle integration](core/nelmio-api-doc.md)
116+
25. [AngularJS Integration](core/angularjs-integration.md)
116117
1. [Restangular](core/angularjs-integration.md#restangular)
117118
2. [ng-admin](core/angularjs-integration.md#ng-admin)
118-
25. [Swagger Support](core/swagger.md)
119+
26. [Swagger Support](core/swagger.md)
119120
1. [Override Swagger documentation](core/swagger.md#override-swagger-documentation)
120-
26. [GraphQL Support](core/graphql.md)
121+
27. [GraphQL Support](core/graphql.md)
121122
1. [Overall View](core/graphql.md#overall-view)
122123
2. [Enabling GraphQL](core/graphql.md#enabling-graphql)
123124
3. [GraphiQL](core/graphql.md#graphiql)
124-
27. [Handling Data Transfer Objects (DTOs)](core/dto.md)
125-
28. [Handling File Upload with VichUploaderBundle](core/file-upload.md)
125+
28. [Handling Data Transfer Objects (DTOs)](core/dto.md)
126+
29. [Handling File Upload with VichUploaderBundle](core/file-upload.md)
126127

127128
## The Schema Generator Component: Generate Data Models from Open Vocabularies
128129

0 commit comments

Comments
 (0)