Introduction
This is the last article of this series. In the previous article we created an application service which used the UserEntityBuilder service to create the entity. Then, the doctrine entity manager (which is an infrastructure service) was used to persist and flush the entity.
Now, it's time to return a result to the presentation layer.
I would like to remember that we have considered the doctrine entities as a domain entities throughout all the articles in the series. I understand that this is not entirely correct and that it would be better to separate the domain entities from the doctrine entities but, for simplicity, I will finish this article using the doctrine entities as domain entities
I am preparing a new article where I will show how i have structured a full Symfony application and there you will see that the domain entities are completely decoupled from doctrine.
Creating an output DTO and an output builder
Before returning the result to the presentation layer, we need to create a DTO to represent the data we want to return. Let's imagine that we only want to return the email, firstName, lastName and dob parameters. Our output DTO would look like this:
readonly class UserOutputDto {
public function __construct(
public string $email,
public string $firstName,
public string $lastName,
public string $dob,
){}
}
Now that the output DTO is ready, it's time to create a service to build the output from an entity. This service will be part of our domain since we decide what information will be part of the output DTO.
class UserOutputDTOBuilder {
public function build(User $user): UserOutputDto
{
return new UserOutputDto(
$user->getEmail(),
$user->getFirstName(),
$user->getLastName(),
$user->getDob()
);
}
}
The output builder is pretty simple, it creates a UserOutputDto passing to the constructor the parameters from the entity values.
This output builder could be part of the application or presentation layer since it does not contain any logic but I will keep it in the domain as I did with the UserEntityBuilder.
Remember that the UserEntityBuilder did contain some extra logic:
- Generate the token
- Generate the current timestamp
Returning the data
Having the output DTO ready, it's time to direct it towards the presentation layer. In our case, what elements make up the presentation layer?. Taking into account that we are going to generate a Symfony JsonResponse and return it as an HTTP response, the controller would be the element which would represent our presentation layer. Let's return to it.
class ApiController extends AbstractController
{
#[Route('/api/entity', name: 'api_v1_post_entity', methods: ['POST'])]
public function saveAction(Request $request, DataProcessor $dataProcessor, UserCreator $userCreator): JsonResponse
{
$userInputDto = $dataProcessor->processData($request->getContent(), UserInputDTO::class);
$userOutputDto = $userCreator->createUser($userInputDto);
return $this->json($userInputDto);
}
}
As part of the presentation layer, the symfony controller uses its infrastructure part (the AbstractController json function) to generate a JsonResponse from the output DTO data ready to be returned within a HTTP response.
As you can see, the symfony controller also uses other application services (DataProcessor and UserCreator) to perform the API call process.
Conclusion
In this final article of the series, we explored the process of returning data to the presentation layer in a Symfony application. We began by creating an output Data Transfer Object (DTO) to encapsulate the user data we wanted to return, specifically the email, first name, last name, and date of birth. We then developed a UserOutputDTOBuilder service to construct this DTO from the user entity, emphasizing the importance of defining what information is included in the output.
Finally, we demonstrated how the Symfony controller acts as the presentation layer, utilizing the JsonResponse functionality to return the DTO data as an HTTP response.
Top comments (0)