In a custom module, I have a form that is triggered by an option in a menu.
I'd want this form to be redirected automatically (without action of the user) to a certain node (/node/2) when the user is not authenticated.
In the public function buildForm(array $form, FormStateInterface $form_state) {, I know how to not display the fields of the form for the anonymous user:

$oCurrentUser = \Drupal::currentUser();
if ($oCurrentUser->isAnonymous()) {
} else {

some fields...    

$form['submit'] = [
  '#type' => 'submit',
  '#value' => $this->t('Submit'),
return $form;

I guess that redirection might be done with $form_state->setRedirect('entity.node.canonical', ['node' => 2]); but I don't know how to make it work...
Any idea?


The class implementing FormInterface is allowed to return an instance of a class extending the Response class, despite FormInterface::buildForm() not documenting it. See what a comment in the FormBuilder::retrieveForm() code says.

Exceptions should not be used for code flow control. However, the Form API currently allows any form builder functions to return a response.
@see https://www.drupal.org/node/2363189

This means that code similar to the following one would actually work.

public function buildForm(array $form, FormStateInterface $form_state) {
  // Verify the currently logged in user is an anonymous user and redirect.
  if ($this->currentUser()->isAnonymous()) {
    return $this->redirect('entity.node.canonical', ['node' => 2]);

Although, since Do not allow form builder functions to return Response objects (the bug report linked in the comment) is open for Drupal 8.8.x, that code could not work anymore, in future.

See also the following comment in the FormBuilder::buildForm() code.

Exceptions should not be used for code flow control. However, the Form API does not integrate with the HTTP Kernel based architecture of Drupal 8. In order to resolve this issue properly it is necessary to completely separate form submission from rendering.
@see https://www.drupal.org/node/2367555

The linked issue is Deprecate EnforcedResponseException support (a task, not a bug report).

A module that works also after the change described in that issue is implemented would:

  • Associate a controller to the route, not a form builder
  • In the controller method associated with the route, redirect the anonymous users to the node page, or render the form for authenticated users

    class RedirectOrFormController extends ControllerBase {
      public function showForm() {
        if ($this->currentUser()->isAnonymous()) {
          return $this->redirect('entity.node.canonical', ['node' => 2]);
        return $this->formBuilder()->getForm('Drupal\\locale\\Form\\TranslateEditForm');

Replace 'Drupal\\locale\\Form\\TranslateEditForm' with the fully qualified name of the form builder.

  • That was my thought precisely, but I wonder how can we do that for ContentEntity forms – rfsbsb May 24 at 14:59

In buildForm() you can return a redirect response the same way as in a controller:

  public function buildForm(array $form, FormStateInterface $form_state) {
    if ($this->currentUser()->isAnonymous()) {
      return $this->redirect('entity.node.canonical', ['node' => 2]);

    // build $form for authenticated users

    return $form;

Use $form_state->setRedirect() if you want to redirect in a form submit handler.

Using buildForm() as controller by specifying _form instead of _controller is documented and widely used (not in FormInterface, but on DO: https://www.drupal.org/docs/8/api/routing-system). It's unlikely core will ask devs to replace it by their own controller.


Using kiamlaluno's advice, the route for the menu is now associated to /association/showMembership.

  path: '/association/showMembership'
    _controller: '\Drupal\association\Controller\MembershipController::showMembership'
    _title: 'Membership'
    _access: 'TRUE'

The controller class uses the following code.

class MembershipController extends ControllerBase {
  public function showMembership() {
    if ($this->currentUser()->isAnonymous()) {
      return $this->redirect('entity.node.canonical', ['node' => 2]);
    return $this->formBuilder()->getForm('Drupal\association\Form\Membership');

The Membership form doesn't redirect users in buildForm().


yes, you are right. you can redirect to the node using the code that you have mentioned. There is another way to set the redirection check the below code.

use the name space :

use Symfony\Component\HttpFoundation\RedirectResponse;
$response = new RedirectResponse(node url);

I don't know what you are trying to achieve hope this code may help you.

  • 1
    exits should not be needed – Kevin Mar 12 at 12:19
  • @Kevin is correct: exit() should not be used. – kiamlaluno Mar 12 at 12:35
  • This is also not how redirects are done in a form builder. – kiamlaluno Mar 14 at 13:38

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.