4

I'm looking for a OOP way to have a simplified User registration form in Drupal 8.

As of today, the default User registration form is declared directly as an annotation in the User class. From the administration pages, it is possible to add a Register form display for the user form. However, when removing all possible fields save for the password/login, there is still a bunch of fields showing up that I want removed:

  • Username
  • Password confirmation
  • Locales settings
  • Contact settings
  • etc.

What I want is an extremely simple registration form, with just two fields: e-mail address and password. All other fields will be editable later. I want this form to use OOP if possible, so extending the class Drupal\user\RegisterForm seems to me a good way to achieve this...

I extended the form but can't use it. It requires an entity to be passed to it apparently, but I don't know how to do that.

The ideal way to do it would be:

$entity = \Drupal::entityTypeManager()
  ->getStorage('user')
  ->create([])
;
$formObject = \Drupal::entityTypeManager()
  ->getFormObject('user', 'register')
  ->setEntity($entity)
;
$registerForm = \Drupal::formBuilder()->getForm($formObject);

However this will insist on fetching the original, non-inherited RegisterForm class, not my custom one. How can I tell Drupal to instanciate my own form instead?

BTW how can I make username optional?

I've seen a few solutions out there for redefining the user registration form, however most of them are Drupal 7 solutions and none of them are OOP.

3
  • tl;dr, username is required since email-only accounts are not supported yet. there is a huge century old issue about this.
    – user21641
    Jun 17, 2017 at 13:35
  • That's fine, I'll find a way to set the Username with the e-mail. That is not the main issue here.
    – Zephyr
    Jun 17, 2017 at 13:41
  • To make username as optional you can use the Email Registration module which make Email address as required field. drupal.org/project/email_registration Through Manage Display Under Configuration > People > Account Settings you can disable the fields that you don't want. Sep 4, 2018 at 9:14

3 Answers 3

6

If you want to use the extended register form class, you need to put it in the place of the original form class in the user entity type:

mymodule.module

  /**
   * Implements hook_entity_type_alter().
   */
  function mymodule_entity_type_alter(array &$entity_types) {
    $entity_types['user']->setFormClass('register', 'Drupal\mymodule\MyRegisterForm');
  }
4

You have to create a custom module and add a service:

@file: my_module.services.yml

  services:
    route_subscriber:
      class: Drupal\my_module\Routing\RouteSubscriber
      tags:
        - {name: event_subscriber }

@file: src/Routing/RouteSubscriber.php

  /**
   * @file
   * Contains \Drupal\my_module\Routing\RouteSubscriber.
   */

  namespace Drupal\my_module\Routing;

  use Drupal\Core\Routing\RouteSubscriberBase;
  use Symfony\Component\Routing\RouteCollection;

  /**
   * Listens to the dynamic route events.
   */
  class RouteSubscriber extends RouteSubscriberBase {

    /**
     * {@inheritdoc}
     */
    protected function alterRoutes(RouteCollection $collection) {
      // login form
      if ($route = $collection->get('user.login')) {
        $route->setDefault('_form', '\Drupal\my_module\Form\NewUserLoginForm');
      }
      // register form
      if ($route = $collection->get('user.register')) {
        $route->setDefault('_form', '\Drupal\my_module\Form\NewUserRegisterForm');
      }

    }
  }

and a custom form class:

@file: src/Form/NewUserRegisterForm.php

  /**
   * @file
   * Contains \Drupal\my_module\Form\NewUserRegisterForm.
   *
   * credits to: https://gist.github.com/davidDuymelinck/cd20ab7049749358717127f12666b68c
   */

  namespace Drupal\my_module\Form;

  use Drupal\Component\Datetime\TimeInterface;
  use Drupal\Core\Entity\EntityFormBuilderInterface;
  use Drupal\Core\Entity\EntityManagerInterface;
  use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
  use Drupal\Core\Extension\ModuleHandlerInterface;
  use Drupal\Core\Form\FormStateInterface;
  use Drupal\Core\Language\LanguageManagerInterface;
  use Drupal\user\Entity\User;
  use Drupal\user\RegisterForm;
  use Symfony\Component\DependencyInjection\ContainerInterface;

  /**
   * Provides a user register form.
   */
  class NewUserRegisterForm extends RegisterForm {
      public function __construct(EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL, ModuleHandlerInterface $moduleHandler) {
          $this->setEntity(new User([], 'user'));
          $this->setModuleHandler($moduleHandler);
          parent::__construct($entity_manager, $language_manager, $entity_type_bundle_info, $time);
      }
      /**
       * @inheritdoc
       */
      public static function create(ContainerInterface $container) {
          return new static(
              $container->get('entity.manager'),
              $container->get('language_manager'),
              $container->get('entity_type.bundle.info'),
              $container->get('datetime.time'),
              $container->get('module_handler')
          );
      }
      public function form(array $form, FormStateInterface $form_state) {
          $form = parent::form($form, $form_state);
          $form['test'] = [
              '#markup' => '<p>Test extended form</p>',
          ];

          return $form;
      }
  }

NB: I did not find how to alter/modify the submit button because $form has no actions key.

1
  • Btw if you modify the class in the user entity type the route will be generated automatically to call the form handler (and to set the new entity which is needed to run the entity form).
    – 4uk4
    Oct 30, 2017 at 10:14
2

I would use the REST resources for creating users instead of hooking into Drupal classes. It is much easier and your frontend guys can completely control the registration experience.

  1. Enable REST and REST UI
  2. Enable /user/register REST route
  3. Edit permissions for this route adding "anonymous access"
  4. Now you send JSON objects to /user/register via ajax
  5. Example:

    $.ajax({
        url: Drupal.url('user/register?_format=json'),
        type: 'POST',
        dataType: 'json',
        data: JSON.stringify(userForm),
        headers: {
            'X-CSRF-Token': csrfToken,
            'Content-type': 'application/json'
        },
    }).done(function(response) {
      console.log('done')
      console.log(response)
    }).fail(function(jqXHR, textStatus) {
      console.log( JSON.parse(jqXHR.responseText))
    });
    
  6. Now your registration form HTML is completely customizable.

Your Answer

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

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