Score:2

In event subscriber, how to redirect if value doesnt exist?

zw flag

I am trying to check a condition before page load, if value exists to load page if not to redirect.

I am following this page

I have created a /mymodule/mymodule.services.yml file and a /mymodule/src/MyModuleSubscriber.php file.

In MyModuleSubscriber.php I would like to check if a value exists, if it does to load site as normal, if the value doesn't exist to perform redirect.

This is the code, but not sure how to write it correctly. Do I need to put an else statement or just leave blank?

Is this correct way to check a value exists on every page load?

class MyModuleSubscriber implements EventSubscriberInterface {

      public function checkForRedirect(GetResponseEvent $event) {

          $baseUrl = $event->getRequest()->getBaseUrl();

          if($value == null &&
             $baseURL !== '/MyModulePage') {
              $event->setResponse(new RedirectResponse($baseUrl.'/MyModulePage'));
          }
      }


  /**
   * {@inheritdoc}
   */
  static function getSubscribedEvents() {
    $events[KernelEvents::REQUEST][] = array('MyModuleLoad', 200);
    return $events;
  }
}

Edit:

      $path = \Drupal::service('path.current')->getPath();

      if($path !== '/MyModulePage') {
          $event->setResponse(new RedirectResponse('/MyModulePage'));
      }
May  avatar
zw flag
Edit: have updated code. What should happen is if visitor doesnt land on /MyModulePage to redirect them to /MyModulePage. But nothing is happening.
4uk4 avatar
cn flag
The service `path.current` is updated during routing, this early you have to get the path from `$event->getRequest()->getPathInfo()`.
May  avatar
zw flag
Hi, still not working. I think its a caching issue? It works some times, other times doesn't. Do I need to run on middleware instead or can I just update the code. I basically need the if statement checked on every page load. Thanks
4uk4 avatar
cn flag
My answer explains how Drupal makes redirects cacheable. If you insist on that your code runs on every page load, which practically means you don't want to cache the redirect at all, then first you have to take care of browser caching, they cache redirects quite aggressively, and second you have to disable the Internal Page Cache. See the [comment](https://drupal.stackexchange.com/questions/278698/disabling-page-cache-for-redirect-response/278703#comment346356_278698) on the topic I've linked at the end of the answer.
Score:4
cn flag

Yes, this is a correct approach. You don't need an else statement. If you don't set a response the event propagation doesn't stop and event subscribers with a lower priority get a chance to set a response. The priority depends on $value. It's unclear in your question, but if it doesn't depend on anything Drupal specific then set a priority >300.

Best practice is to use a cacheable response and add any dependencies of $value to the response. If you don't have any then still use this response. It tells Drupal that you are fine with that it is cached how you want to redirect this path.

Example:

core/lib/Drupal/Core/EventSubscriber/RedirectLeadingSlashesSubscriber.php

<?php

namespace Drupal\Core\EventSubscriber;

use Drupal\Core\Cache\CacheableRedirectResponse;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
 * Redirects paths starting with multiple slashes to a single slash.
 */
class RedirectLeadingSlashesSubscriber implements EventSubscriberInterface {

  /**
   * Redirects paths starting with multiple slashes to a single slash.
   *
   * @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
   *   The RequestEvent to process.
   */
  public function redirect(RequestEvent $event) {
    $request = $event->getRequest();
    // Get the requested path minus the base path.
    $path = $request->getPathInfo();

    // It is impossible to create a link or a route to a path starting with
    // multiple leading slashes. However if a form is added to the 404 page that
    // submits back to the same URI this presents an open redirect
    // vulnerability. Also, Drupal 7 renders the same page for
    // http://www.example.org/foo and http://www.example.org////foo.
    if (strpos($path, '//') === 0) {
      $path = '/' . ltrim($path, '/');
      $qs = $request->getQueryString();
      if ($qs) {
        $qs = '?' . $qs;
      }
      $event->setResponse(new CacheableRedirectResponse($request->getUriForPath($path) . $qs));
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events[KernelEvents::REQUEST][] = ['redirect', 1000];
    return $events;
  }

}

If $value is Drupal specific, for example you get it from an entity, use the default priority 0 and set the entity as cache dependency. In this case you need to set response headers to prevent that the browser is caching the redirect result for this path. Use LocalRedirectResponse for local or TrustedRedirectResponse for external URLs. See this great answer Disabling Page Cache for Redirect Response

May  avatar
zw flag
Hi @4k4 I have updated my post. What should happen is if the visitor doesn't land on MyModulePage to be redirected to MyModulePage. However nothing is happening. Thanks
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.