De MVC a DDD Parte III - Moviendo la lógica de negocio a un servicio
Refactor mover parte de la lógica del controlador a un servicio
Antes de nada comentar que si tienes el repositorio en tu local hay que cambiar de rama.
git checkout blog-publish-mvc-v2
Como podemos apreciar, el controlador ya no se encarga de realizar la lógica de publicación.
Esta parte se delega al servicio
PostPublishService
que tiene este aspecto:
public function __construct(UserRepository $userRepository, PostRepository $postRepository)
{
$this->userRepository = $userRepository;
$this->postRepository = $postRepository;
}
public function execute(int $userId, int $postId): PostEntity
{
$user = $this->userRepository->ofIdOrFail($userId);
$post = $this->postRepository->ofIdOrFail($postId);
$post->publish();
$this->postRepository->save($post);
$this->notifyToUser($post, $user);
return $post;
}
private function notifyToUser(PostEntity $post, UserEntity $user): void
{
pr("sending email ...");
mb_send_mail(
$user->email(),
"Your post with id {$post->id()} has been published",
"Congrats! your post has been published"
);
pr("monologging ...");
(new Monolog())->log("Post with title {$post->title()} published by user {$user->email()}");
}
Un pequeño paréntesis. Por costumbre mis clases suelen ser de tipo final sean de cualquier tipo (entidades, repositorios, servicios, controladores, etc).
Esto evita que de primeras nadie pueda heredar de ellas con lo que me aseguro que todo lo que modifique en su contenido tendrá el mínimo efecto colateral.
Al mismo tiempo procuro que todo sea de ámbito privado y que en la medida de lo posible los únicos métodos públicos sean el __construct() e
__invoke(). Esto hace que el objeto instanciado esté menos acoplado al sistema.
Si necesito usar herencia y por ende tener acceso a sus atributos entonces quito el final y cambio a protected. Si es estrictamente necesario
y tengo que hacer un método público lo cambio a public. Aquí dejo un video del creador de doctrine que explica el porqué.
Marco Pivetta: Extremely defensive PHP
Volviendo al código anterior... He creado el namespace Services, una capa extra. La capa de servicios o Service layer.
Vemos que en el constructor se inyectan los dos repositorios. Si bien en el controlador hacemos new MiRepositorio()
no deberíamos proceder de este modo, tendríamos que optar por la inyección de dependencias. Para efectos didácticos nos vale.
Si deseas saber el porqué de la inyección te dejo un video de CodelyTv que lo explica muy bien.
SOLID - Principio de Inversión de Dependencias
Si ejecutamos la aplicación deberíamos ver las mismas trazas en amarillo y el contenido del post. (tal y como en la rama inicial)
- Volver a: Refactorizando de MVC a DDD Parte 2 - ¿Porqué llevar la lógica de negocio a un servicio?
- Continuar con: Refactoriazando de MVC a DDD Parte 4 - Reorganizando las carpetas de MVC a estructura DDD incluyendo namespaces
Dejo el video de CodelyTv donde tocan este tema. El refactor de controlador a servicio: DEJA DE USAR EL PATRÓN MVC
Autor: Eduardo A. F.
Publicado: 12-04-2022 21:09
Actualizado: 29-04-2022 23:04