16

In Drupal 7, I use the following code.

function my_goto($path) { 
  drupal_goto($path, array(), 301);
}

What code should I use in Drupal 8?

1
  • 3
    drupal.org/node/2023537 is the change record for drupal_goto(), whenever you are looking for a replacement for a specific function, look there first.
    – Berdir
    Dec 3 '14 at 8:24
31

This is the code that should be used in Drupal 8. See change Record for more info.

use Symfony\Component\HttpFoundation\RedirectResponse;

function my_goto($path) { 
  $response = new RedirectResponse($path);
  $response->send();
  return;
}
2
15
+50

First (but read on for the correct, better aproach) it's important to note that Drupal 9.2 broke the simple way of doing it:

$response = new RedirectResponse($path);
$response->send();

You have to use the full code from the drupal_goto() changelog, namely:

$response = new RedirectResponse($url->toString());
$request = \Drupal::request();
// Save the session so things like messages get saved.
$request->getSession()->save();
$response->prepare($request);
// Make sure to trigger kernel events.
\Drupal::service('kernel')->terminate($request, $response);
$response->send();

Still, this solution is not OK in many cases. One prominent case is using it in hooks like eg. many modules that provide redirection after user login. Redirecting inside a hook means that the chain of hooks gets broken, there will be other hooks that don't get a chance to run after yours. This is wrong. The proper way to do it has been different for some time.

You create a middleware service that can be used for the purpose. Put this into src/Middleware/Redirect.php:

namespace Drupal\yourmodule\Middleware;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;

class Redirect implements HttpKernelInterface {
  protected $httpKernel;
  protected $redirectResponse;

  public function __construct(HttpKernelInterface $http_kernel) {
    $this->httpKernel = $http_kernel;
  }

  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
    $response = $this->httpKernel->handle($request, $type, $catch);
    return $this->redirectResponse ?: $response;
  }

  public function setRedirectResponse(?RedirectResponse $redirectResponse) {
    $this->redirectResponse = $redirectResponse;
  }

}

refer to it in your services.yml:

services:
  http_middleware.yourmodule_redirect:
    class: Drupal\yourmodule\Middleware\Redirect
    tags:
      - { name: http_middleware }

and use it like any other service:

$url = Url::fromRoute('<front>', [], ['absolute' => 'true']);
$response = new RedirectResponse($url->toString());
\Drupal::service('http_middleware.yourmodule_redirect')->setRedirectResponse($response);

Yes, slightly more code, although the service can be reused any time, of course, calling it is simple enough. But this solution will not immediately halt execution, it will note your redirect request, do the proper thing and redirect on the next turn. A solution like that might get added to the core itself because there are places that would benefit from it, but until then, use your own, doing it correctly.

Credit goes to: https://www.drupal.org/project/redirect_after_login/issues/3214949

2
  • Just a note that if you do your redirect in Rules, Rules takes care of all the code for you so you don't have to worry about writing and maintaining your own service, you don't have to worry about redirecting too early and causing hooks not to run, or any of that other stuff. The redirect can be configured in the Rules UI without writing any code. And the best part is that the way Rules does things didn't break in 9.2 - it works on all versions of Drupal.
    – anonymous
    Jul 11 at 0:46
  • 2
    Could well be. However, most of us who ask and answer on this site are programmers who are more interested in solutions in code rather than mousing around in the UI. :-) If the question of how to do something in your own code comes up, installing a complete module instead is not the ususal solution we look for.
    – Gábor
    Jul 12 at 7:32
9

To build on Anu Mathew's response;

To add a status code, its just the second param in the RedirectResponse class;

use Symfony\Component\HttpFoundation\RedirectResponse;

function my_goto($path) { 
  $response = new RedirectResponse($path, 302);
  $response->send();
  return;
}
2
7

This can be achieved by leveraging built-in symphonies EventDispatcher Component. All you have to do is create a custom module. Add your services.yml file and provide appropriate service config.

services:
  mymodue.subscriber:
    class: Drupal\my_module\EventSubscriber
    tags:
      - { name: event_subscriber }

in Your modules src directory add the EventSubscriber.php class and describe you methods here.

<?php
namespace Drupal\my_module;

use Drupal\Core\Url;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;

class EventSubscriber implements EventSubscriberInterface {

  public function checkForCustomRedirect(RequestEvent $event) {    
    $request = $event->getRequest(); 
    $route_name = $request->attributes->get('_route');
    if($route_name === 'module.testPage') {
      $url = Url::fromRoute('<front>')->toString();
      $event->setResponse(new RedirectResponse($url));
    }
  }
      
  /**
  * {@inheritdoc}
  */
  public static function getSubscribedEvents() {
    return [KernelEvents::REQUEST => [['checkForCustomRedirect']]];
  }
}
1
  • $url is not defined. Dec 27 '19 at 18:59
6

I didn't work in drupal 8 yet but as per the documentation drupal_goto is removed from Drupal 8.

In place of drupal_goto you need to write:

return new RedirectResponse(\Drupal::url('route.name'));

and something like this with parameters :

return new RedirectResponse(\Drupal::url('route.name', [], ['absolute' => TRUE]));

Check here https://www.drupal.org/node/2023537 and class RedirectResponse

15
  • 1
    Thanks for your reply.But how can i get the route name from the current url(Because url is setting using configuration form)
    – Anu Mathew
    Dec 3 '14 at 5:48
  • 1
    You mean redirect path is dynamic??? Dec 3 '14 at 5:52
  • 1
    Yes, your right its dynamic..
    – Anu Mathew
    Dec 3 '14 at 5:55
  • 1
    Ok try to replace \Drupal::url('route.name') with your url or perhaps absolute url. Dec 3 '14 at 6:03
  • 1
    return new RedirectResponse($absolute_url); is worked for me :) But its showing "redirect to example.com/absolute_url " message on the screen
    – Anu Mathew
    Dec 3 '14 at 6:15
4

Never use $response->send() under any circumstances. This results in unpredictable behavior and might fail in different environments, when moving from dev to prod, for example, or in future updates, like it did for Drupal 9.2.

The correct method depends on where you want to use it:

2

Perfectly working redirect code for me is the following:

$response = new RedirectResponse($path);
return $response->send();

In any other cases I'm getting some kind of exceptions or errors, for example: LogicException: The controller must return a response...

OR

https://www.drupal.org/project/drupal/issues/2852657

There is already a discussion about it, hope that helps!

2

this works for internal or external redirection:

use Symfony\Component\HttpFoundation\RedirectResponse;
use Drupal\Core\Url;

   $url = Url::fromUri('internal:/node/27'); // choose a path
   // $url =  Url::fromUri('https://external_site.com/');
    $destination = $url->toString();
    $response = new RedirectResponse($destination, 301);
    $response->send();

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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