Explicaciones sobre los servicios en Laravel, una manera de adelgazar los controladores llevándote lógica de negocio a clases aparte, que puedes reutilizar. Ventajas y modos de implementar servicios en tus aplicaciones.
En este artículo vamos a explicar una práctica común en Laravel, que puedes usar para organizar de una manera más adecuada el código de las aplicaciones. Aunque acalaro que posiblemente ya estás implementando esta práctica, a pesar que quizás no le habías dado este nombre.
La pieza de software que queremos presentar se llama "servicio". Antes de comenzar conviene aclarar que no se trata de una de las piezas "core" del framework, sino más bien una convención de la comunidad que se hace para fomentar buenas prácticas.
Qué es un service
En Laravel, un "service" se refiere generalmente a una clase que encapsula cierta lógica de negocio, que queremos mantener de una manera independiente y reutilizable.
La idea de los servicios consiste en separar ciertos procesos de los controladores y otros componentes, con el objetivo de mejorar la organización y mantenibilidad del código.
Estas clases no son un concepto nativo formal como los controladores o middlewares, sino una convención común en la comunidad para manejar operaciones complejas, de modo que podamos modularizar más todavía las tareas frecuentes de nuestras aplicaciones.
Qué buenas prácticas fomentan los servicios
Como hemos dicho, los servicios se pueden usar para adelgazar el código de los controladores, separando aquellas partes en las que puedas delegar a otras clases. Algunos de los beneficios que conseguimos son los siguientes:
- Descargamos de responsabilidad a los controladores, haciendo que sean más sencillos de mantener
- Centralizamos la lógica de negocio, permitiendo una mejor reutilización
- Facilita las pruebas unitarias
- Se integra bien con otras piezas de Laravel, aparte de los controladores y además con el service container para la inyección de dependencias
Creación de servicios
Dado que los servicios (o services) no forman parte de los artefactos que Laravel propone de entrada, no existe una manera específica fija de crear su scaffolding en Laravel, es decir, no hay un comando de artisan especialmente pensado para ellos. Por tanto, las decisiones de las carpetas donde los podrás crear dependen un poco de ti.
Una convención posible sería crear una carpeta dentro de "app" llamada "Services" para crear allí tus clases de servicios, pero nada te impide que uses una carpeta como app/Lib en vez de app/Services.
No obstante, si lo prefieres, puedes lanzar un comando de artisan para generar una clase "genérica":
php artisan make:class Services/MiService
Ese comando te creará la clase y el namespace adecuado según la ruta de la clase que le has indicado, en este caso services/MiService.
Un servicio tendrá un código totalmente arbitrario, según lo que necesites hacer, por lo que no hay una estructura que debas seguir. No obstante, por poner un ejemplo vamos a ver un posible servicio que calculase el precio de un producto, atendiendo a un posible descuento y un posible tipo de IVA.
Ese servicio lo podríamos tener en el archivo app/Services/PriceCalculator.php y podría verse así:
<?php
namespace App\Services;
class PriceCalculator
{
private float $taxRate;
private float $discountRate;
public function __construct(float $taxRate = 0.21, float $discountRate = 0.0)
{
$this->taxRate = $taxRate;
$this->discountRate = $discountRate;
}
public function setTaxRate(float $taxRate): self
{
$this->taxRate = $taxRate;
return $this;
}
public function setDiscountRate(float $discountRate): self
{
$this->discountRate = $discountRate;
return $this;
}
public function calculate(float $basePrice): float
{
$priceWithDiscount = $basePrice - ($basePrice * $this->discountRate);
$priceWithTax = $priceWithDiscount + ($priceWithDiscount * $this->taxRate);
return round($priceWithTax, 2);
}
}
Gracias a este servicio ya no necesitarás calcular a mano los valores de los precios finales en los controladores, sino que podrás apoyarte en él para conseguir centralizar y reutilizar esta operativa.
Diferencia con helpers
Si ya trabajas con Laravel conocerás perfectamente los helpers que son funciones estáticas simples que nos permiten ejecutar funcionalidades comunes dentro del framework.
Los helpers están muy bien porque son muy simples de utilizar, pero no son siempre la opción más potente.
Un helper es adecuado cuando tienes que hacer una tarea simple y ya está. Sin embargo, apoyarse en clases tiene numerosas ventajas como la posibilidad de guardar estado, aparte de muchos otros beneficios que te aportan la programación orientada a objetos, autoloading, solucionar problemas de colisiones, etc.
Es por tanto importante que cuando desarrollemos en la Laravel tendamos hacia los servicios el lugar de funciones sueltas o helpers, ya que nos ofrecerán mucha más versatilidad.
Servicios y su integración con el Service Container de Laravel
Los servicios son buenos candidatos para inyectar en los controladores, middlewares, rutas, jobs y toda una serie de clases del framework Laravel. Esto hace que el código de los distintos artefactos sea más fácilmente testable.
El service Container es una de las piezas más importantes de la arquitectura de Laravel que veremos más adelante. Pero ya podemos adelantar que nos permite entregar de una manera sencilla instancias de clases allá donde se necesitan.
En muchas ocasiones el service container o contenedor de servicios de Laravel funcionará de manera automática pero si no es así lo puedes configurar con distintas estrategias, de modo que quede perfectamente definido el proceso para crear instancias y configurarlas.
En el siguiente artículo vamos a comenzar a hablar del Service container para que obtengas más información útil para entender cómo funciona.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...