Verified Commit 31b727dc authored by Dave Long's avatar Dave Long
Browse files

fix: #3573856 SiteConfigureForm properties need to be reset after module install in submitForm()

By: godotislate
By: smustgrave
By: nicxvan
parent 20e9a3ae
Loading
Loading
Loading
Loading
Loading
+18 −2
Original line number Diff line number Diff line
@@ -261,13 +261,15 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
    $update_status_module = $form_state->getValue('enable_update_status_module');
    if (empty($install_state['config_install_path']) && $update_status_module) {
      $this->moduleInstaller->install(['update']);
      // After a module is installed, there is a new container, so all class
      // properties dependent on the container need to be reset.
      $this->resetPropertiesFromContainer();

      // Add the site maintenance account's email address to the list of
      // addresses to be notified when updates are available, if selected.
      $email_update_status_emails = $form_state->getValue('enable_update_status_emails');
      if ($email_update_status_emails) {
        // Reset the configuration factory so it is updated with the new module.
        $this->resetConfigFactory();
        // Reset the configuration so it is updated with the new module.
        $this->config('update.settings')->set('notification.emails', [$account_values['mail']])->save(TRUE);
      }
    }
@@ -315,4 +317,18 @@ protected function getAdminRoles(): array {
    return $this->entityTypeManager->getStorage('user_role')->loadByProperties(['is_admin' => TRUE]);
  }

  /**
   * Repopulate class properties from container.
   */
  protected function resetPropertiesFromContainer(): void {
    $this->resetConfigFactory();
    $container = \Drupal::getContainer();
    $this->root = $container->getParameter('app.root');
    $this->sitePath = $container->getParameter('site.path');
    $this->entityTypeManager = $container->get('entity_type.manager');
    $this->moduleInstaller = $container->get('module_installer');
    $this->userNameValidator = $container->get('user.name_validator');
    $this->superUserAccessPolicy = $container->getParameter('security.enable_super_user') ?? TRUE;
  }

}
+37 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\testing_site_config\Hook;

use Drupal\Core\Hook\Attribute\Hook;
use Symfony\Component\DependencyInjection\Attribute\Autowire;

/**
 * Simulates a hook class with a dependency chain requiring the kernel.
 *
 * During an interactive site installation, if 'Check for updates automatically'
 * is checked, the update module will be installed in the submit handler of the
 * site configure form. After that, the user 1 entity is loaded to be populated
 * with values from the form. This leads to hook implementations (the user_load
 * hook in this instance) to be called. However, since the container was rebuilt
 * when the update module was installed, all the service properties in
 * SiteConfigureForm, such as entityTypeManager, need to re-populated from the
 * newly-built container, otherwise they will reference outdated objects and
 * cause exceptions.
 *
 * @see \Drupal\Core\Installer\Form\SiteConfigureForm::submitForm()
 */
class TestingSiteConfigHooks {

  public function __construct(
    #[Autowire(service: 'kernel')]
    protected $kernel,
  ) {}

  #[Hook('user_load')]
  public function userLoad(): void {
    assert(isset($this->kernel));
  }

}
+5 −0
Original line number Diff line number Diff line
@@ -48,6 +48,10 @@ protected function installParameters() {
    // from our install profile.
    unset($parameters['forms']['install_configure_form']['site_mail']);

    // Set 'enable_update_status_module' flag to test that
    // SiteConfigureForm::submit() handles the container rebuild correctly after
    // the Update Status module is installed.
    $parameters['forms']['install_configure_form']['enable_update_status_module'] = TRUE;
    return $parameters;
  }

@@ -67,6 +71,7 @@ protected function setUpSite() {
  public function testInstaller(): void {
    $this->assertEquals(self::EXPECTED_SITE_MAIL, $this->config('system.site')->get('mail'));
    $this->assertEquals(self::EXPECTED_TIMEZONE, $this->config('system.date')->get('timezone.default'));
    $this->assertTrue(\Drupal::moduleHandler()->moduleExists('update'));
  }

}