Sometimes there is an objective to redirect the user somewhere using the data in GET. In Drupal 10 to make a redirect we have to create event subscriber service.
Let's imagine we need to redirect to the node page in case we have nid in GET. So e.g. while open an URL like /news?nid=42 user should be redirected to /node/42. Here is the solution.
First, we have to define event subscriber in services.yml:
services:
# Name of this service.
snippets.event_subscriber:
# Event subscriber class that will listen for the events.
class: Drupal\snippets\EventSubscriber\RedirectSubscriber
# Tagged as an event_subscriber to register this subscriber with the event_dispatch service.
tags:
- {name: event_subscriber}
arguments: ['@entity_type.manager']
Code of event subscriber:
<?php
namespace Drupal\snippets\EventSubscriber;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Class RedirectSubscriber for performing task on page request.
*
* @package Drupal\custom_events\EventSubscriber
*/
class RedirectSubscriber implements EventSubscriberInterface {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* {@inheritdoc}
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager) {
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*
* @return array
* The event names to listen for, and the methods that should be executed.
*/
public static function getSubscribedEvents() {
$events[KernelEvents::REQUEST][] = array('nidRedirect');
return $events;
}
/**
* Handles redirect to node page if nid is in GET.
*
* @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
* The event to process.
*/
public function nidRedirect(RequestEvent $event) {
// Getting the value of "nid" GET parameter.
if ($nid = $event->getRequest()->query->get('nid')) {
// Getting node with specified nid.
$nodes = $this->entityTypeManager->getStorage('node')->loadByProperties(['nid' => $nid]);
$node = reset($nodes);
if ($node instanceof NodeInterface) {
$event->setResponse(new RedirectResponse($node->toUrl()->toString(), 301));
}
}
}
}
With this logic, it's also possible to solve many other tasks. For example, using routeMatch service we could get a node object from the current route and based on some node's field value redirect the user somewhere. E.g. here if we need to redirect to the homepage in case the node has bool field_homepage_redirect set to TRUE:
/**
* Handles redirect to homepage if current node's field_homepage_redirect is set to TRUE.
*
* @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
* The event to process.
*/
public function homepageRedirect(RequestEvent $event) {
// We must be sure it's node page.
// @todo use dependency injection here :)
if ($node = \Drupal::routeMatch()->getParameter('node')) {
// We also need to be sure the field exists and is not empty (set to TRUE).
if ($node->hasField('field_homepage_redirect') && !$node->get('field_homepage_redirect')->isEmpty()) {
$event->setResponse(new RedirectResponse(Url::fromRoute('<front>')->toString(), 301));
}
}
}