logo

Extra Block Types (EBT) - Nueva experiencia con Layout Builder❗

Extra Block Types (EBT): tipos de bloques con estilo y personalizables: Presentaciones de diapositivas, Pestañas, Tarjetas, Acordeones y muchos más. Configuraciones integradas para fondo, DOM Box y plugins de JavaScript. Experimenta hoy el futuro de la construcción de diseños.

Módulos de demostración EBT Descargar módulos EBT

❗Extra Paragraph Types (EPT) - Nueva experiencia con Paragraphs

Extra Paragraph Types (EPT): conjunto de módulos basado en párrafos de forma análoga.

Módulos de demostración EPT Descargar módulos EPT

Scroll

Restringir el acceso al vocabulario de términos de taxonomía utilizando un Event Subscriber

11/06/2025, by Ivan

Menu

A veces necesitas Categorías fijas y permanentes en el sitio, que no deben actualizarse accidentalmente. En este caso, puedes utilizar código personalizado con un Event Subscriber.

Vamos a agregar una nueva clase Event Subscriber en un módulo personalizado.

drupalbook_custom.services.yml

services:  
  drupalbook_custom.tag_redirect_subscriber:
    class: Drupal\drupalbook_custom\EventSubscriber\TagRedirectSubscriber
    arguments:
      - '@entity_type.manager'
      - '@current_user'
    tags:
      - { name: event_subscriber }

Y añadimos nuestro Event Subscriber en drupalbook_custom/src/EventSubscriber/TagRedirectSubscriber:

<?php

namespace Drupal\drupalbook_custom\EventSubscriber;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Redirige a los no administradores desde las páginas de administración del vocabulario "Tag".
 *
 * Un subscriber a nivel de Request se ejecuta temprano, permitiéndonos interrumpir
 * la solicitud y devolver una redirección antes de que se ejecute el controlador correspondiente.
 */
class TagRedirectSubscriber implements EventSubscriberInterface {

  /**
   * El servicio de gestor de tipos de entidad.
   *
   * Se mantiene como dependencia de ejemplo; no es estrictamente necesario para la lógica actual,
   * pero resulta útil si en el futuro se requieren operaciones sobre entidades.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected EntityTypeManagerInterface $entityTypeManager;

  /**
   * El servicio de usuario actual (proxy).
   *
   * Se utiliza para comprobaciones rápidas de roles, permitiendo evitar la redirección para
   * los administradores.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected AccountProxyInterface $currentUser;

  /**
   * Constructor del subscriber.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   El gestor de tipos de entidad.
   * @param \Drupal\Core\Session\AccountProxyInterface $current_user
   *   El usuario que realiza la solicitud.
   */
  public function __construct(
    EntityTypeManagerInterface $entity_type_manager,
    AccountProxyInterface $current_user,
  ) {
    $this->entityTypeManager = $entity_type_manager;
    $this->currentUser = $current_user;
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents(): array {
    // La prioridad 32 asegura que los parámetros de ruta estén disponibles,
    // pero el controlador aún no ha sido ejecutado.
    return [
      KernelEvents::REQUEST => ['onKernelRequest', 32],
    ];
  }

  /**
   * Realiza la redirección cuando un usuario no administrador accede a rutas de administración de "Tag".
   *
   * @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
   *   El evento del kernel que transporta la solicitud.
   */
  public function onKernelRequest(RequestEvent $event): void {
    // Actuar solo sobre la solicitud principal (master).
    if (!$event->isMainRequest()) {
      return;
    }

    // Permitir a los administradores continuar sin redirección.
    if ($this->currentUser->hasRole('administrator')) {
      return;
    }

    $request = $event->getRequest();
    $route_name = $request->attributes->get('_route');

    // Destino para todos los intentos bloqueados.
    $redirect_to = 'https://drupalbook.org/admin/structure'
      . '/taxonomy/manage/tag/overview';

    switch ($route_name) {
      case 'entity.taxonomy_vocabulary.overview_form':
      case 'entity.taxonomy_vocabulary.overview_terms':
      case 'entity.taxonomy_term.add_form':
        // Confirmar que se trata del vocabulario "tag".
        $vocabulary = $request->attributes->get('taxonomy_vocabulary');
        if (!empty($vocabulary) && $vocabulary->id() === 'tag') {
          $event->setResponse(new TrustedRedirectResponse($redirect_to));
        }
        return;

      case 'entity.taxonomy_term.edit_form':
      case 'entity.taxonomy_term.delete_form':
        /** @var \Drupal\taxonomy\Entity\Term|null $term */
        $term = $request->attributes->get('taxonomy_term');
        // bundle() devuelve el nombre de máquina del vocabulario.
        if ($term && $term->bundle() === 'tag') {
          $event->setResponse(new TrustedRedirectResponse($redirect_to));
        }
        return;

      default:
        return;
    }
  }

}

La clase TagRedirectSubscriber es un Event Subscriber personalizado para Drupal, diseñado para restringir el acceso a las páginas de administración de un vocabulario de taxonomía específico (en este caso, "tag") a los usuarios que no sean administradores. Aquí tienes un desglose de su estructura y los aspectos clave presentes en el código:

1. Propósito y caso de uso

  • Objetivo: Evitar actualizaciones accidentales o no autorizadas en el vocabulario "tag" redirigiendo a los usuarios no administradores fuera de sus rutas administrativas.
  • Beneficio: Proporciona una capa de control de acceso basada en la interfaz (UI/UX) para vocabularios críticos, garantizando la estabilidad de categorías fijas.

2. Estructura de la clase y dependencias

  • La clase implementa EventSubscriberInterface, haciéndola compatible con el sistema de eventos de Symfony usado por Drupal.
  • Dependencias inyectadas mediante el constructor:
    • EntityTypeManagerInterface: Incluida para posibles operaciones futuras con entidades. No es necesaria para la lógica actual, pero facilita la extensibilidad.
    • AccountProxyInterface: Utilizada para recuperar y comprobar de manera eficiente los roles del usuario actual.
    La inyección de dependencias asegura que el subscriber sea testeable, reutilizable y se ajuste a las buenas prácticas del contenedor de servicios de Drupal.

3. Eventos suscritos

  • La clase se suscribe al evento KernelEvents::REQUEST con una prioridad de 32.
    Esta prioridad garantiza:
    • Que los parámetros de ruta ya están resueltos.
    • Que el controlador de la ruta aún no se ha ejecutado, permitiendo al subscriber interceptar y detener la solicitud con una redirección si es necesario.

4. Lógica de redirección

  • El método onKernelRequest() realiza todas las comprobaciones de acceso y la lógica de redirección:
    • Actúa solo sobre la solicitud principal: Evita la gestión duplicada en sub-solicitudes.
    • Permite a los administradores: Si el usuario tiene el rol administrator, siempre se le permite el acceso.
    • Comprueba los nombres de las rutas: Solo considera ciertas rutas relacionadas con el vocabulario de taxonomía o sus términos.
    • Redirige a los no administradores:
      • Para rutas de vista general, añadir o listar (entity.taxonomy_vocabulary.overview_form, entity.taxonomy_vocabulary.overview_terms, entity.taxonomy_term.add_form), comprueba si el vocabulario es tag.
      • Para rutas de edición y eliminación (entity.taxonomy_term.edit_form, entity.taxonomy_term.delete_form), comprueba si el bundle() del término (nombre de máquina del vocabulario) es tag.
    • Utiliza una redirección confiable (TrustedRedirect): Si se cumplen las condiciones, el usuario es redirigido a una página segura de administración del vocabulario "tag".
  • Extensibilidad: La lógica es fácil de ampliar para incluir otros vocabularios o roles ajustando las condiciones.

5. Seguridad y buenas prácticas

  • Intercepción temprana: Al ejecutarse sobre el evento de la solicitud, el subscriber puede aplicar restricciones de acceso antes de que se procese o muestre cualquier dato sensible.
  • Omisión basada en roles: Comprueba eficientemente los roles de usuario para no bloquear a administradores o constructores del sitio.
  • Separación clara de responsabilidades: Mantiene la lógica de rutas, comprobaciones de usuario y redirecciones claramente separadas para facilitar el mantenimiento.

6. Posibles mejoras

  • Ya que EntityTypeManagerInterface está inyectado, puedes agregar fácilmente comprobaciones basadas en entidades en el futuro (por ejemplo, permisos basados en propiedades específicas del término o contenido relacionado).
  • Puedes generalizar la clase para gestionar múltiples vocabularios o proporcionar redirecciones personalizables mediante configuración.

7. Conclusiones clave

  • Este Event Subscriber demuestra un enfoque práctico para el control de acceso en Drupal, aprovechando la arquitectura orientada a eventos de Symfony para gestionar las solicitudes de forma temprana y eficiente.
  • El enfoque es ideal para proteger vocabularios de taxonomía que solo deben ser gestionados por usuarios de confianza, reduciendo el riesgo de cambios accidentales.