0

Not sure if this is a related/duplicate of Generate unique form ID based on context

I am hoping I can render a unique form per user with the Form API using a custom form class.

What I've seen with \Drupal::formBuilder()->getForm(), you must provide your Form::class and this does not allow for something like:

public function getFormId() {

  $userID = \Drupal::currentUser()->id();
  $userFormID = 'form_settings' . $userID;
  return $userFormID;

}

and returns an invalid form with \Drupal::formBuilder()->getForm().

Ultimately trying to render a unique form via hook_preprocess_page() for the user to interact with.


An idea of what I have so far is a simple form with two submit items.

MYMODULE\src\Form\Form.php:

public function buildForm(array $form, FormStateInterface $form_state) {

  $config = \Drupal::config('MYMODULE.MYMODULE_settings');

  $form['description'] = [
    '#type' => 'item',
    '#markup' => $messageMarkup,
  ];

  $form['time'] = [
    '#type' => 'hidden',
    '#default_value' => time(),
  ];

  $form['form_delay'] = [
    '#type' => 'submit',
    '#value' => $this->t('Remind Me'),
    '#submit' => ['::submitFormDelay'],
  ];

  $form['form_ignore'] = [
    '#type' => 'submit',
    '#value' => $this->t('Ignore'),
    '#submit' => ['::submitFormIgnore'],
  ];

  return $form;

}

public function submitFormDelay(array &$form, FormStateInterface $form_state) {

  $values = $form_state->getValues();

  $this->configFactory->getEditable('MYMODULE.MYMODULE_settings')
    ->set('time', $values['time'])
    ->save();

  parent::submitForm($form, $form_state);

}

public function submitFormIgnore(array &$form, FormStateInterface $form_state) {

  $this->configFactory->getEditable('MYMODULE.MYMODULE_settings')
    ->set('time', NULL)
    ->save();

  parent::submitForm($form, $form_state);

}

Then grabbing the time value to see if I should show the form

MYMODULE.module:

function MYMODULE_preprocess_page(&$variables) {

  $config = \Drupal::config('MYMODULE.MYMODULE_settings');

  // Comes from another form controller in the module.
  $reminderDelay = $otherFormConfig->get('reminder_delay');

  $timeAtInteraction = $config->get('time') ?: NULL;

  $timeForm = \Drupal::formBuilder()
    ->getForm(\Drupal\my_module\Form\Form::class);

  if ($timeAtInteraction != NULL) {

    if ($timeAtInteraction < (time() - $reminderDelay)) {
      // Provide our form to page.html.twig.
      $variables['timeForm'] = $timeForm;
    }

  }

}

The form works, but of course, a single user sets it for everyone. I'd like the form/values to be unique per user.

Is it possible using the Form API?

(Working on cache contexts as suggested below, but not included above.)

  • As an alternative for my needs, I've tried working with $this->messenger()->addMessage() and something like drupal.org/project/messageclose, but it just doesn't give some features like persistence, time-based values, etc... so am hoping forms can do it. – Prestosaurus Mar 23 at 17:08
  • 3
    I'm not sure why you want to add the current user ID to the form ID. This makes sense only if you render forms for multiple users on the same page, but there is only one current user. If you want to render a form specific to the current user you have to add a user cache context to the form. – 4k4 Mar 23 at 17:29
  • That may be my missing piece. I want the same form, but unique to the user. The user id was my attempt to distinguish form settings by user. I will look at form cache contexts. (similar functionally would be the "accept cookies" forms you see, using form API) – Prestosaurus Mar 23 at 17:41
  • 1
    In the context of Drupal, 'the same form but unique to the user' does not make sense. What do you mean by 'unique to the user', and what is your goal? You've told us how you have tried to go about solving some problem, but you haven't told us the problem you are trying to solve, or the goal you are trying to reach. – Jaypan Mar 24 at 1:33
  • Thanks, @Jaypan, I have updated my question. I hope that clarifies. – Prestosaurus Mar 24 at 2:10
2

Your updated post shows the issue. The issue here isn't the form, it's the underlying storage method. You are using configuration, which is for site configuration, ie configure how the site as a whole works. But you want to save values per user, not for the whole site.

What you are looking for is having a form used by all users, saving the submitted values for the user, rather than for the site.

I would suggest using the user.data service. This service lets you save data for users. You can user UserData::set() to set values, and UserData::get() to get values. Get the values in the form definition to get the default value, and set the values in the submit handlers to update them with the current values.

As a side note, if you were creating a form for configuration (which you're not), you would want to extend ConfigFormBase, which it doesn't appear you were doing, based on your code.

  • That really is an elegant solution. I was even thinking I might need to save to user data table and was not aware of this service. – Prestosaurus Mar 24 at 4:17

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.