As of Drupal 8 drupal_goto()
has been removed in favor of RedirectResponse which comes together with the Symfony HttpFoundation.
hook_drupal_goto_alter()
was also removed as well, in favor of just using an event listener on kernel.response
Redirecting
Drupal 7
function my_menu_callback_foo() {
//....
drupal_goto('user');
}
Drupal 8 (procedural)
use Symfony\Component\HttpFoundation\RedirectResponse;
function my_menu_callback_foo() {
//....
return new RedirectResponse(\Drupal\Core\Url::fromRoute('user.page')->toString());
}
Drupal 8 (properly injected)
use Drupal\Core\Controller\ControllerBase;
class MyControllerClass extends ControllerBase {
public function foo() {
//...
return $this->redirect('user.page');
}
}
If the route name is not known use RedirectResponse
with a URL. When redirecting to an external location, use TrustedRedirectResponse
. (Note that if Drupal has a destination set, it will unexpectedly override all redirects).
use Drupal\Core\Controller\ControllerBase;
class MyControllerClass extends ControllerBase {
public function foo() {
//...
return new TrustedRedirectResponse('https://example.com/some/path'); // for eg. Url::fromUserInput(\Drupal::destination()->get())->setAbsolute()->toString();
}
}
Note: #2023445: Improve DX of doing a redirect might change the way this is handled.
Altering the redirection URL:
D7
/**
* Implements hook_drupal_goto_alter().
*/
function mymodule_drupal_goto_alter(&$path, &$options, &$http_response_code) {
if ($path == 'http://example.com') {
$path = 'http://example2.com';
}
}
D8
in mymodule.services.yml
:
services:
mymodule.subscriber:
class: Drupal\mymodule\EventSubscriber\MyModuleSubscriber
tags:
- { name: event_subscriber }
namespace Drupal\mymodule\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class MyModuleSubscriber implements EventSubscriberInterface {
public function checkRedirection(FilterResponseEvent $event) {
$response = $event->getResponse();
if ($response instanceOf RedirectResponse && $response->getTargetUrl() == 'http://example.com') {
$response->setTargetUrl('http://example2.com');
}
}
static function getSubscribedEvents() {
$events[KernelEvents::RESPONSE][] = ['checkRedirection'];
return $events;
}
}
Redirecting to the same page
You should avoid doing this dynamic lookup and specify the route you wish to redirect to.
Note that all usages of this in core were replaced by specific redirects.
Drupal 7
function my_menu_callback_foo() {
//....
drupal_goto();
}
Drupal 8
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Routing\RouteMatch;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
class MyControllerClass extends ControllerBase {
public function foo(Request $request) {
$route_match = $route = RouteMatch::createFromRequest($request);
//...
return $this->redirect($route_match->getRouteName(), $route_match->getRawParameters()->all());
}
}
Redirecting to the home page
Drupal 7
function my_menu_callback_foo() {
//....
drupal_goto('');
}
Drupal 8
use Drupal\Core\Controller\ControllerBase;
class MyControllerClass extends ControllerBase {
public function foo(Request $request) {
//...
return $this->redirect('<front>');
}
}
Redirecting when not in context of a controller
$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();
Comments
The RedirectResponse object
The RedirectResponse object doesn't allow for external redirects anymore. For external redirects use \Drupal\Core\Routing\TrustedRedirectResponse:
Redirect to specific node page or path
In preprocess, redirect to node with an anchor
Our business logic demanded a redirect in a preprocess. This page had an anchor/fragment.
So redirecting to https://example.com/node-19-alias#conclusion
Can be achieved by:
Hakuna Matata
Is "Redirecting when not in context of a controller" working?
Is "Redirecting when not in context of a controller" still working or is it triggers an error like this for others too?
See: https://www.drupal.org/project/webform/issues/3380667
I recently had some caching
I recently had some caching issues with the "Redirecting when not in context of a controller". And without knowing about the existing
EnforcedResponseException
solution, I implemented an almost identical workaround.I'll make a shameless plug to an article where I summarize the implementation: https://blog.birk-jensen.dk/drupal-http-redirection-from-anywhere