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

GLightbox is a pure javascript lightbox (Colorbox alternative without jQuery)❗

It can display images, iframes, inline content and videos with optional autoplay for YouTube, Vimeo and even self-hosted videos.

Demo GLightbox Download GLightbox

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.