Skip to content

Commit 4ccf7f8

Browse files
committed
Fix messenger documentation
1 parent 98a06f9 commit 4ccf7f8

File tree

2 files changed

+75
-66
lines changed

2 files changed

+75
-66
lines changed

core/data-persisters.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,3 +147,41 @@ services:
147147
#arguments: ['@App\DataPersister\UserDataPersister.inner']
148148
#tags: [ 'api_platform.data_persister' ]
149149
```
150+
151+
## Calling multiple DataPersisters
152+
153+
Our DataPersisters are called in chain, once a data persister is supported the chain breaks and API Platform assumes your data is persisted. You can call mutliple data persisters by implementing the `ResumableDataPersisterInterface`:
154+
155+
```php
156+
namespace App\DataPersister;
157+
158+
use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
159+
use App\Entity\BlogPost;
160+
161+
final class BlogPostDataPersister implements ContextAwareDataPersisterInterface, ResumableDataPersisterInterface
162+
{
163+
public function supports($data, array $context = []): bool
164+
{
165+
return $data instanceof BlogPost;
166+
}
167+
168+
public function persist($data, array $context = [])
169+
{
170+
// call your persistence layer to save $data
171+
return $data;
172+
}
173+
174+
public function remove($data, array $context = [])
175+
{
176+
// call your persistence layer to delete $data
177+
}
178+
179+
// Once called this data persister will resume to the next one
180+
public function resumable(array $context = []): bool
181+
{
182+
return true;
183+
}
184+
}
185+
```
186+
187+
This is very useful when using [`Messenger` with API Platform](messenger.md) as you may want to do something asynchronously with the data but still call the default Doctrine data persister.

core/messenger.md

Lines changed: 37 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -18,99 +18,81 @@ docker-compose exec php \
1818

1919
## Dispatching a Resource through the Message Bus
2020

21-
Set the `messenger` attribute to `true`, and API Platform will automatically dispatch the API Resource instance as a message using the message bus provided by the Messenger Component:
21+
Set the `messenger` attribute to `true`, and API Platform will automatically dispatch the API Resource instance as a message using the message bus provided by the Messenger Component. The following example allows you to create a new `Person` in an asynchronous manner:
2222

2323
[codeSelector]
2424

2525
```php
2626
<?php
27-
// api/src/Entity/ResetPasswordRequest.php
27+
// api/src/Entity/Person.php
2828

2929
namespace App\Entity;
3030

3131
use ApiPlatform\Core\Annotation\ApiResource;
3232
use Symfony\Component\Validator\Constraints as Assert;
33-
34-
/**
35-
* @ApiResource(
36-
* messenger=true,
37-
* collectionOperations={
38-
* "post"={"status"=202}
39-
* },
40-
* itemOperations={},
41-
* output=false
42-
* )
43-
*/
44-
final class ResetPasswordRequest
33+
use ApiPlatform\Core\Action\NotFoundAction;
34+
35+
#[ApiResource(collectionOperations: [
36+
"post" => ["messenger" => true, "output" => false, "status" => 202]
37+
], itemOperations: [
38+
"get" => ["controller" => NotFoundAction::class, "read" => false, "status" => 404]
39+
]
40+
)]
41+
final class Person
4542
{
43+
#[ApiProperty(identifier: true)]
44+
public string $id;
45+
4646
/**
47-
* @var string
48-
*
4947
* @Assert\NotBlank
5048
*/
51-
public $username;
49+
public string $name;
5250
}
5351
```
5452

5553
```yaml
5654
# api/config/api_platform/resources.yaml
5755
resources:
58-
App\Entity\ResetPasswordRequest:
56+
App\Entity\Person:
5957
collectionOperations:
6058
post:
6159
status: 202
62-
itemOperations: []
63-
attributes:
6460
messenger: true
6561
output: false
62+
itemOperations:
63+
get:
64+
status: 404
65+
controller: ApiPlatform\Core\Action\NotFoundAction
66+
read: false
6667
```
6768
6869
[/codeSelector]
6970
70-
Because the `messenger` attribute is `true`, when a `POST` is handled by API Platform, the corresponding instance of the `ResetPasswordRequest` will be dispatched.
71+
Because the `messenger` attribute is `true`, when a `POST` is handled by API Platform, the corresponding instance of the `Person` will be dispatched.
7172

72-
For this example, only the `POST` operation is enabled.
73+
For this example, only the `POST` operation is enabled. We disabled the item operation using the `NotFoundAction`. A resource must have at least one item operation as it must be identified by an IRI, here the route `/people/1` exists, eventhough it returns a 404 status code.
7374
We use the `status` attribute to configure API Platform to return a [202 Accepted HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202).
7475
It indicates that the request has been received and will be treated later, without giving an immediate return to the client.
75-
Finally, the `output` attribute is set to `false`, so the HTTP response that will be generated by API Platform will be empty, and the [serialization process](serialization.md) will be skipped.
76-
77-
**Note:** when using `messenger=true` ApiResource attribute in a Doctrine entity, the Doctrine DataPersister is not called. You must use the `messenger="persist"` ApiResource attribute.
78-
79-
**Note:** when using `messenger="input"` ApiResource attribute in a Doctrine entity, the Doctrine DataPersister is not called. You must use an array containing `persist` and `input` if you want it to be called, for example:
80-
81-
[codeSelector]
82-
83-
```php
84-
/**
85-
* @ApiResource(messenger={"persist", "input"})
86-
*/
87-
```
76+
Finally, the `output` attribute is set to `false`, so the HTTP response that will be generated by API Platform will be empty, and the [serialization process](serialization.md) will be skipped.
8877

89-
```yaml
90-
resources:
91-
# ...
92-
attributes:
93-
messenger: ['persist', 'input']
94-
```
95-
96-
[/codeSelector]
78+
**Note:** when using `messenger=true` ApiResource attribute in a Doctrine entity, the Doctrine DataPersister is not called. If you want the Doctrine DataPersister to be called, you should implement a `ResumableDataPersisterInterface` [documented here](data-persisters.md).
9779

9880
## Registering a Message Handler
9981

10082
To process the message that will be dispatched, [a handler](https://symfony.com/doc/current/messenger.html#registering-handlers) must be created:
10183

10284
```php
10385
<?php
104-
// api/src/Handler/ResetPasswordRequestHandler.php
86+
// api/src/Handler/PersonHandler.php
10587
10688
namespace App\Handler;
10789
108-
use App\Entity\ResetPasswordRequest;
90+
use App\Entity\Person;
10991
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
11092
111-
final class ResetPasswordRequestHandler implements MessageHandlerInterface
93+
final class PersonHandler implements MessageHandlerInterface
11294
{
113-
public function __invoke(ResetPasswordRequest $forgotPassword)
95+
public function __invoke(PersonHandler $person)
11496
{
11597
// do something with the resource
11698
}
@@ -137,7 +119,7 @@ To differentiate typical persists calls (create and update) and removal calls, c
137119

138120
## Using Messenger with an Input Object
139121

140-
Set the `messenger` attribute to `input`, and API Platform will automatically dispatch the given Input as a message instead of the Resource. Indeed, it'll add a default `DataTransformer` ([see input/output documentation](./dto.md)) that handles the given `input`.
122+
Set the `messenger` attribute to `input`, and API Platform will automatically dispatch the given Input as a message instead of the Resource. Indeed, it'll add a default `DataTransformer` ([see input/output documentation](./dto.md)) that handles the given `input`. In this example, we'll handle a `ResetPasswordRequest` on a custom operation on our `User` resource:
141123

142124
```php
143125
<?php
@@ -148,17 +130,11 @@ namespace App\Entity;
148130
use ApiPlatform\Core\Annotation\ApiResource;
149131
use App\Dto\ResetPasswordRequest;
150132
151-
/**
152-
* @ApiResource(
153-
* collectionOperations={
154-
* "post"={"status"=202}
155-
* },
156-
* itemOperations={},
157-
* messenger="input",
158-
* input=ResetPasswordRequest::class,
159-
* output=false
160-
* )
161-
*/
133+
#[ApiResource(collectionOperations: [
134+
"post", "get", "delete"
135+
"reset_password" => ["status" => 202, "messenger" => "input", "input" => SomeInput::class, "output" => false, "method" => "POST", "path" => "/users/reset_password"]
136+
]
137+
)]
162138
final class User
163139
{
164140
}
@@ -175,20 +151,15 @@ use Symfony\Component\Validator\Constraints as Assert;
175151
176152
final class ResetPasswordRequest
177153
{
178-
/**
179-
* @var string
180-
* @Assert\NotBlank
181-
*/
182-
public $var;
154+
public string $username;
183155
}
184156
```
185157

186-
For this example, only the `POST` operation is enabled on `/users`.
187158
As above, we use the `status` attribute to configure API Platform to return a [202 Accepted HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/202).
188159
It indicates that the request has been received and will be treated later, without giving an immediate return to the client.
189160
Finally, the `output` attribute is set to `false`, so the HTTP response that will be generated by API Platform will be empty, and the [serialization process](serialization.md) will be skipped.
190161

191-
In this case, when a `POST` request is issued on `/users` the message handler will receive an `App\Dto\ResetPasswordRequest` object instead a `User` because we specified it as `input` and set `messenger=input`:
162+
In this case, when a `POST` request is issued on `/users/reset_password` the message handler will receive an `App\Dto\ResetPasswordRequest` object instead a `User` because we specified it as `input` and set `messenger=input`:
192163

193164
```php
194165
<?php

0 commit comments

Comments
 (0)