0

Hello Drupal Code Land,

I have created a custom admin form in a custom module as a class extending ConfigFormBase. I use this form as an admin config form to set pricing options for different variables used with a custom content type (called estimates) where the form settings are used having been passed in from drupalSettings and are used in a js file containing several custom Drupal.behaviors to calculate pricing interactively when creating a new estimate.

This all works 100% beautifully.

The problem (which isn't a huge problem) that I'm facing, is I've started going back through things cleaning up code and in a couple cases I have changed the names of several of the custom admin form fields. This appears to be causing the old named form fields with their set value to remain in drupalSettings in addition to the new form fields (modified fields) and their values.

Upon viewing the config form where I can change the form field values to update the form settings the old form fields aren't there (which they shouldn't be) so why are they still present in drupalSettings? I would have assumed they would be removed from drupalSettings once the form is resaved with any updated values, yet they are not...they remain!

I've cleared all caches in a browser on the site, and I've used drush cashe:rebuild several times which doesn't have any affect.

So I'm fairly certain I'm missing something probably in modules config form, but haven't been able to find any specific documentation regarding removal of "no-longer in existence" form field settings from drupalSettings. I've found how to override but not remove...

Here is the a snippet of the submit form function:

 public function submitForm(array &$form, FormStateInterface $form_state) {
        parent::submitForm($form, $form_state);
        $this->config('newlooks.pricesettings')
          ->set('estimate_gutter_install_base_price', $form_state->getValue('estimate_gutter_install_base_price'))

// a lot more of ->set()'s for form fields

          ->save();
 }

Thinking about it now a little more - Do I need some kind of rebuild form within the submit? Or something in the buildForm function to get drupalSettings or Drupal to remove the fields and data no-longer present in buildForm or submit functions?

Here is a snip of the buildForm function as well:

 public function buildForm(array $form, FormStateInterface $form_state) {
        $config = $this->config('newlooks.pricesettings');

        // Lots and lots of $form[estimate_something_base_price] = []
        // fields to display...

        
        return parent::buildForm($form, $form_state);
 }

I'm also trying to avoid dumping it directly from the DB which would be a quick fix (and not overly difficult) but really wouldn't solve this issue in the future as I will probably make more changes to the form over time.

Oh, and I'm currently working with Drupal 9.4.8

Thank You!

Update Edit:

using:

function newlooks_update_9101() {
  \Drupal::configFactory()->getEditable('newlooks.settings')->clear('estimate_gutter_cover_size_five');
}
  • did not clear the key in question

tried:

function newlooks_update_9102() {
  \Drupal::configFactory()->getEditable('newlooks.settings')->delete('estimate_gutter_cover_size_five');
}
  • and it deleted all the settings not the keyed one

This for my particular use case is not ideal having to run an update hook each time a configuration/settings form is edited. Seeing that if I add new form elements to the buildForm function and they become available instantly there has to be a better method.

I feel this over time could lead to a huge .module file with endless update hooks (as your not supposed to remove them once added).

Don't get me wrong hook_update_N() will work it just seams drastic.

Is there not some way to rebuild the settings or purge settings in another manor where I could actually use the existing form key:values to check against removing key:value pairs that no-longer exist?

I really feel there should be something that can handle that, another hook perhaps that runs anytime cache is cleared (just shooting in the dark on that) but something!

I definitely thank you Jaypan, I will need to use hook_update_N() else where at some point - it's just if I can avoid it in this use case it would be ideal.

Update Edit: I'll try to add a little clarity!

So in my buildForm function for example I started with this:

$form['estimate_gutter_cover_size_five'] = [
            '#type' => 'number',
            '#group' => 'cover_sizes',
            '#step' => '.01',
            '#prefix' => '<div class="gutters gtcovers gtcovers-size estimate-form-item">',
            '#title' => $this->t('5 inch Covers'),
            '#description' => $this->t('This is the base price for a standard gutter cover size <em>and is multiplied by quantity in feet for a total cost.</em>'),
            '#min' => '0.00',
            '#max' => '999.99',
            '#placeholder' => '0.00',
            '#default_value' => $config->get('estimate_gutter_cover_size_five_base_price'),
            '#suffix' => '</div>',
            '#required' => TRUE,
        ];

But later I went back and changed that to:

$form['estimate_gutter_cover_size_five_base_price'] = [
            '#type' => 'number',
            '#group' => 'cover_sizes',
            '#step' => '.01',
            '#prefix' => '<div class="gutters gtcovers gtcovers-size estimate-form-item">',
            '#title' => $this->t('5 inch Covers'),
            '#description' => $this->t('This is the base price for a standard gutter cover size <em>and is multiplied by quantity in feet for a total cost.</em>'),
            '#min' => '0.00',
            '#max' => '999.99',
            '#placeholder' => '0.00',
            '#default_value' => $config->get('estimate_gutter_cover_size_five_base_price'),
            '#suffix' => '</div>',
            '#required' => TRUE,
        ];

I open the form in a web browser and replace the placeholder with a value as it is now seen as a new element. Does exactly what I want aside from leaving garbage in the settings that aren't readily visible. Only reason I noticed it was I wanted to check variables on page load so in my js file I added: console.log(window);

While inspecting them via browser console I saw drupalSettings and figured what the heck I'll take a peak.

Upon viewing I saw both:

  • estimate_gutter_cover_size_five: "2.37"
  • estimate_gutter_cover_size_five_base_price: "2.37"

Having changed estimate_gutter_cover_size_five to estimate_gutter_cover_size_five_base_price I would have expected that estimate_gutter_cover_size_five would have been removed but was not. Considering I had to open the form for settings in a browser and set/add the new/changed elements value (where the old element and value is no longer displayed, in my mind it was "should be" gone).

Now that is just one element/field on a form with probably about 70 now and it will be growing and changing as I build everything moving forward.

That in combination with the fact I do a lot of quick testing sometimes/many times not properly naming things in reference to everything else it is or needs to be associated with, using hook_update_N() isn't going to be very helpful.

6
  • Using ->clear() will delete the key. So the question is why it didn't work for you. Did you run the database update script? Was your implementation of hook_update_n() executed? What was the output of the update script? And how did you determine that this did not work - after running the update script, what did you do to check this value?
    – Jaypan
    Nov 18, 2022 at 20:12
  • You could also just use drush cdel on all environments that the key needs to be deleted from, if you have access to them all. But the stable way to do it is to use hook_update_N().
    – Jaypan
    Nov 18, 2022 at 20:13
  • also note that drupalSettings refers to a JavaScript object, which has nothing to do with your code. I believe you are referring to 'active configuration'.
    – Jaypan
    Nov 18, 2022 at 20:15
  • Yes I ran the update script when attempting to use clear and it did nothing...the key was still there with value in drupalSettings. The update script ran without error nothing was reported in logs, no errors. I have access to everything drush is installed so using drush cdel shouldn't be a problem, I'm going to look that up now.. thank you
    – sidgrafix
    Nov 18, 2022 at 20:17
  • 1
    I tried 3 times using ->clear exactly how it is listed in my question I copied the code right from my file and pated it up there. So you got me there. Drush however I think will work ideally. Using drush config:edit newlooks.settings I can delete directly or output that to a file in tmp dir and use it to do diff compare to get a list of what needs to be removed and maybe throw a little script on it to then take that list and use drush config:delete key_name which is drush cdel. That was most helpful, thank you..
    – sidgrafix
    Nov 18, 2022 at 20:42

2 Answers 2

1

Configuration snapshots are stored in cache, and therefore are cleared with a cache clear, but the base value is still part of the system's active configuration, and will be part of the rebuilt configuration snapshot. This is why clearing the cache isn't removing your configuration.

The way to deal fix your issue is to implement hook_update_N(), and either remove unused keys from the configuration, or if the entire configuration object needs removal, delete it.

function HOOK_update_N() {
  // Delete a key from a configuration object. For example, to 
  // delete example_module.settings.some_key:
  \Drupal::configFactory()->getEditable('example_module.settings')->clear('some_key');

  // Or, you can delete an entire config object, if none of the keys
  // are necessary any longer. For example, to delete example_module.settings:
  \Drupal::configFactory()->getEditable('example_module.settings')->delete();
}
3
  • So this kinda worked. But not really friendly. Tried twice using clear and it did absolutely nothing.
    – sidgrafix
    Nov 18, 2022 at 19:14
  • It did absolutely nothing, but kind of worked? Those seem contradictory.
    – Jaypan
    Nov 18, 2022 at 19:17
  • time expired I tried to edit my comment: ...the setting was still present. Then the 3rd time used ->delete but entered a key instead of just delete all, but it cleared them all which isn't what I wanted to do. So have to refill the entire config form again, not ideal. Plus to be honest having to add a new update hook every time a class base form is updated or changed seams a bit counterintuitive being I need the visible set form fields values to stay. I'll update my question some - but Thank You for the info
    – sidgrafix
    Nov 18, 2022 at 19:22
0

Instead of setting single values you could set the entire array:

public function submitForm(array &$form, FormStateInterface $form_state) {
  $data = [];
  $data['estimate_gutter_install_base_price'] = $form_state->getValue('estimate_gutter_install_base_price');

  // add more values

  $this->config('newlooks.pricesettings')
    ->setData($data)
    ->save();

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

Or you can even try to use the form values structure if you have defined the form build accordingly:

public function submitForm(array &$form, FormStateInterface $form_state) {
    // Get all values.
    $values = $form_state->getValues();

    // Remove Form API values.
    unset(
      $values['form_build_id'],
      $values['form_token'],
      $values['form_id'],
      $values['op'],
      $values['actions']
    );

    // Save config.
    $this->config('webform_example_custom_form.settings')
      ->setData($values)
      ->save();

    // Display message.
    parent::submitForm($form, $form_state);
  }

}

Found this in the great Webform module.

1
  • This sound promising...and more inline with what I'm looking for! I'm going to try this first thing when I'm back at it on Monday (packing it up for the weekend right now). Thinking the second of the 2 approaches you suggest will work with my existing buildForm and allow me to eliminate what would probably turn into an endless grow list of ->set()->save. Thank You 4uk4.. If this works I'll set both of the answers I received as correct with a depending on actual use case. Thank you both for all the help and info.
    – sidgrafix
    Nov 18, 2022 at 21:44

Your Answer

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

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