5

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'));
      }
4
  • Edit: have updated code. What should happen is if visitor doesnt land on /MyModulePage to redirect them to /MyModulePage. But nothing is happening.
    – May
    Nov 8, 2021 at 14:07
  • The service path.current is updated during routing, this early you have to get the path from $event->getRequest()->getPathInfo().
    – 4uk4
    Nov 8, 2021 at 14:27
  • 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
    – May
    Nov 9, 2021 at 10:52
  • 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 on the topic I've linked at the end of the answer.
    – 4uk4
    Nov 9, 2021 at 13:59

1 Answer 1

5

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

1
  • 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
    – May
    Nov 8, 2021 at 14:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.