You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: core/state-processors.md
+156-2Lines changed: 156 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -5,10 +5,13 @@ classes called **state processors**. State processors receive an instance of the
5
5
the `#[ApiResource]` attribute). This instance contains data submitted by the client during [the deserialization
6
6
process](serialization.md).
7
7
8
-
A state processor using [Doctrine ORM](https://www.doctrine-project.org/projects/orm.html) is included with the library and
8
+
With the Symfony variant, a state processor using [Doctrine ORM](https://www.doctrine-project.org/projects/orm.html) is included with the library and
9
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/current/reference/basic-mapping.html).
10
10
A [Doctrine MongoDB ODM](https://www.doctrine-project.org/projects/mongodb-odm.html) state processor is also included and can be enabled by following the [MongoDB documentation](mongodb.md).
11
11
12
+
With the Laravel variant, a state processor using [Eloquent ORM](https://laravel.com/docs/eloquent) is included with the library and
13
+
is enabled by default. It is able to persist and delete objects that are also mapped as [Related Models](https://laravel.com/docs/eloquent-relationships#inserting-and-updating-related-models).
14
+
12
15
However, you may want to:
13
16
14
17
- store data to other persistence layers (Elasticsearch, external web services...)
@@ -20,6 +23,7 @@ process the data for a given resource will be used.
20
23
21
24
## Creating a Custom State Processor
22
25
26
+
### Custom State Processor with Symfony
23
27
If the [Symfony MakerBundle](https://symfony.com/doc/current/bundles/SymfonyMakerBundle) is installed in your project, you can use the following command to generate a custom state processor easily:
24
28
25
29
```console
@@ -75,8 +79,64 @@ use App\State\BlogPostProcessor;
75
79
class BlogPost {}
76
80
```
77
81
82
+
### Custom State Processor with Laravel
83
+
Using [Laravel Artisan Console](https://laravel.com/docs/artisan), you can generate a custom state processor easily with the following command:
84
+
```console
85
+
php artisan make:state-processor
86
+
```
87
+
88
+
To create a state processor, you have to implement the [`ProcessorInterface`](https://github.com/api-platform/core/blob/main/src/State/ProcessorInterface.php).
89
+
This interface defines a method `process`: to create, delete, update, or alter the given data in any ways.
final class BlogPostProcessor implements ProcessorInterface
107
+
{
108
+
/**
109
+
* @return BlogPost|void
110
+
*/
111
+
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
112
+
{
113
+
// call your persistence layer to save $data
114
+
return $data;
115
+
}
116
+
}
117
+
```
118
+
119
+
The `process()` method must return the created or modified object, or nothing (that's why `void` is allowed) for `DELETE` operations.
120
+
The `process()` method can also take an object as input, in the `$data` parameter, that isn't of the same type that its output (the returned object). See [the DTO documentation entry](dto.md) for more details.
121
+
122
+
We then configure our operation to use this processor:
123
+
124
+
```php
125
+
<?php
126
+
// api/app/Models/BlogPost.php
127
+
128
+
namespace App\Models;
129
+
130
+
use ApiPlatform\Metadata\Post;
131
+
use App\State\BlogPostProcessor;
132
+
133
+
#[Post(processor: BlogPostProcessor::class)]
134
+
class BlogPost {}
135
+
```
136
+
78
137
## Hooking into the Built-In State Processors
79
138
139
+
### Symfony State Processor mechanism
80
140
If you want to execute custom business logic before or after persistence, this can be achieved by using [composition](https://en.wikipedia.org/wiki/Object_composition).
81
141
82
142
Here is an implementation example which uses [Symfony Mailer](https://symfony.com/doc/current/mailer.html) to send new users a welcome email after a REST `POST` or GraphQL `create` operation, in a project using the native Doctrine ORM state processor:
@@ -151,7 +211,101 @@ use App\State\UserProcessor;
151
211
class User {}
152
212
```
153
213
154
-
## Registering Services Without Autowiring
214
+
### Laravel State Processor mechanism
215
+
If you want to execute custom business logic before or after persistence, this can be achieved by using [composition](https://en.wikipedia.org/wiki/Object_composition).
216
+
217
+
Here is an implementation example which uses [Laravel Mail](https://laravel.com/docs/mail) to send new users a welcome email after a REST `POST` or GraphQL `create` operation, in a project using the native Eloquent ORM state processor:
218
+
219
+
```php
220
+
<?php
221
+
// api/app/State/UserProcessor.php
222
+
223
+
namespace App\State;
224
+
225
+
use ApiPlatform\Metadata\DeleteOperationInterface;
226
+
use ApiPlatform\Metadata\Operation;
227
+
use ApiPlatform\State\ProcessorInterface;
228
+
use App\Models\User;
229
+
use Symfony\Component\DependencyInjection\Attribute\Autowire;
230
+
use Symfony\Component\Mailer\MailerInterface;
231
+
232
+
/**
233
+
* @implements ProcessorInterface<User,User|void>
234
+
*/
235
+
final class UserProcessor implements ProcessorInterface
236
+
{
237
+
public function __construct(
238
+
private ProcessorInterface $persistProcessor,
239
+
private ProcessorInterface $removeProcessor,
240
+
)
241
+
{
242
+
}
243
+
244
+
/**
245
+
* @return User|void
246
+
*/
247
+
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
248
+
{
249
+
if ($operation instanceof DeleteOperationInterface) {
0 commit comments