Curso de desarrollo en Drupal 10
La inyección de dependencias es un patrón de diseño que permite gestionar las dependencias entre objetos de manera eficiente y flexible. En Drupal, la inyección de dependencias se utiliza para acceder a los servicios del contenedor de servicios sin usar directamente la clase estática \Drupal::service(), lo que mejora la mantenibilidad, la legibilidad del código y facilita las pruebas unitarias.
¿Qué es la inyección de dependencias?
La inyección de dependencias es un método para pasar objetos o servicios que una clase necesita (sus dependencias) desde fuera de la clase, generalmente a través del constructor. En Drupal, esto se hace implementando el método create() de la interfaz ContainerInjectionInterface.
Ventajas de la inyección de dependencias:
- Facilita la prueba del código: Las dependencias se pueden «simular» (mock) fácilmente para pruebas.
- Mejora la legibilidad y la organización del código: Es más claro qué servicios está utilizando un controlador.
- Evita el uso de servicios estáticos: Promueve un diseño de código más limpio y modular.
Ejemplo básico de inyección de dependencias en un controlador
- Crea un archivo de controlador en
modules/custom/mi_modulo/src/Controller/MiControlador.php. - Define la clase del controlador con inyección de dependencias.
Código de ejemplo:
namespace Drupal\mi_modulo\Controller;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Messenger\MessengerInterface;
class MiControlador extends ControllerBase {
/**
* Servicio de base de datos.
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
/**
* Servicio de mensajería.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* Constructor.
*
* @param \Drupal\Core\Database\Connection $database
* El servicio de conexión a la base de datos.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* El servicio de mensajería.
*/
public function __construct(Connection $database, MessengerInterface $messenger) {
$this->database = $database;
$this->messenger = $messenger;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('database'),
$container->get('messenger')
);
}
/**
* Método que muestra un mensaje usando el servicio de mensajería.
*
* @return array
* Un array renderizable.
*/
public function mostrarMensaje() {
$this->messenger->addMessage('Este es un mensaje de prueba usando el servicio de mensajería.');
return [
'#markup' => '<p>Mensaje enviado correctamente.</p>',
];
}
}
Explicación del código:
__construct(): Se utiliza para definir las dependencias que la clase necesita (en este caso, la conexión a la base de datos y el servicio de mensajería).create(): Método estático que implementa la inyección de dependencias usando el contenedor de servicios de Drupal. Este método es requerido cuando se utiliza la inyección de dependencias en controladores.$this->messenger->addMessage(): Utiliza el servicio inyectado para mostrar un mensaje al usuario.
Pasos para usar inyección de dependencias en un controlador:
- Declara las propiedades que contendrán las dependencias.
- Implementa el constructor (
__construct()) para asignar esas propiedades. - Crea el método
create()para devolver una nueva instancia de la clase con las dependencias necesarias.
¿Cómo se registra la ruta para este controlador?
Crea una ruta en el archivo mi_modulo.routing.yml:
mi_modulo.mostrar_mensaje:
path: '/mostrar-mensaje'
defaults:
_controller: '\Drupal\mi_modulo\Controller\MiControlador::mostrarMensaje'
_title: 'Mensaje desde el controlador'
requirements:
_permission: 'access content'
Esta ruta conectará la URL /mostrar-mensaje con el método mostrarMensaje() del controlador MiControlador.
Inyección de múltiples servicios
Puedes inyectar tantos servicios como necesites en un controlador. Solo asegúrate de definir todos los servicios en el constructor y obtenerlos correctamente en el método create().
Ejemplo con múltiples servicios:
namespace Drupal\mi_modulo\Controller;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\Messenger\MessengerInterface;
class OtroControlador extends ControllerBase {
protected $currentUser;
protected $messenger;
public function __construct(AccountProxyInterface $currentUser, MessengerInterface $messenger) {
$this->currentUser = $currentUser;
$this->messenger = $messenger;
}
public static function create(ContainerInterface $container) {
return new static(
$container->get('current_user'),
$container->get('messenger')
);
}
public function mostrarUsuario() {
$username = $this->currentUser->getDisplayName();
$this->messenger->addMessage('Usuario actual: ' . $username);
return [
'#markup' => '<p>Nombre de usuario mostrado en un mensaje.</p>',
];
}
}
Explicación:
- Se inyecta el servicio
current_userpara obtener información sobre el usuario logueado. - Se utiliza el método
getDisplayName()para obtener el nombre del usuario y mostrarlo en un mensaje.
Beneficios de la inyección de dependencias en controladores
- Facilidad de pruebas: La inyección de dependencias permite la simulación de servicios, facilitando la prueba unitaria del código.
- Modularidad y limpieza: El código es más modular y fácil de mantener porque no depende de la clase estática
\Drupal::service(). - Claridad del código: Es más fácil entender qué servicios están siendo utilizados en el controlador al observar su constructor.
Conclusión
La inyección de dependencias en controladores es una práctica recomendada en Drupal porque mejora la estructura del código y facilita las pruebas y la mantenibilidad. Al seguir este patrón, tu código será más robusto, flexible y adherente a las mejores prácticas de desarrollo.