diff --git a/core/dto.md b/core/dto.md new file mode 100644 index 00000000000..4d240e83a61 --- /dev/null +++ b/core/dto.md @@ -0,0 +1,116 @@ +# Handling Data Transfer Objects (DTOs) + +## How to use a DTO for Writing + +Sometimes it's easier to use a DTO than an Entity when performing simple +operation. For example, the application should be able to send an email when +someone has lost its password. + +So let's create a basic DTO for this request: + +```php +// api/src/Api/Dto/ForgotPasswordRequest.php + +namespace App\Api\Dto; + +use ApiPlatform\Core\Annotation\ApiResource; +use Symfony\Component\Validator\Constraints as Assert; + +/** + * @ApiResource( + * collectionOperations={ + * "post"={ + * "method"="POST", + * "path"="/users/forgot-password-request", + * }, + * }, + * itemOperations={}, + * ) + */ +final class ForgotPasswordRequest +{ + /** + * @Assert\NotBlank() + * @Assert\Email() + */ + public $email; +} +``` + +In this case, we disable all operations except `POST`. + +Then, thanks to [the event system](events.md), it's possible to intercept the +`POST` request and to handle it. + +First, an event subscriber is needed: + +```php +userManager = $userManager; + } + + public static function getSubscribedEvents() + { + return [ + KernelEvents::VIEW => ['sendPasswordReset', EventPriorities::POST_VALIDATE], + ]; + } + + public function sendPasswordReset(GetResponseForControllerResultEvent $event) + { + $request = $event->getRequest(); + + if ('api_forgot_password_requests_post_collection' !== $request->attributes->get('_route')) { + return; + } + + $forgotPasswordRequest = $event->getControllerResult(); + + $user = $this->userManager->findOneByEmail($forgotPasswordRequest->email); + + // We do nothing if the user does not exist in the database + if ($user) { + $this->userManager->requestPasswordReset($user); + } + + $event->setResponse(new JsonResponse(null, 204)); + } +} +``` + +Then this class should be registered as a service, then tagged. + +If service autowiring and autoconfiguration are enabled (it's the case by +default), you are done! + +Otherwise, the following configuration is needed: + +```yaml +# app/config/services.yml +services: + + # ... + + 'App\Api\EventSubscriber\UserSubscriber': + arguments: + - '@app.manager.user' + tags: [ 'kernel.event_subscriber' ] +``` diff --git a/index.md b/index.md index 24e46d44fb7..76ccd687cad 100644 --- a/index.md +++ b/index.md @@ -112,6 +112,7 @@ 1. [Overall Process](core/serialization.md#overall-process) 2. [Available Serializers](core/serialization.md#available-serializers) 3. [Decorating a Serializer and Add Extra Data](core/serialization.md#decorating-a-serializer-and-add-extra-data) +27. [Handling Data Transfer Objects (DTOs)](core/dto.md) ## The Schema Generator Component: Generate Data Models from Open Vocabularies