Commit 6e84b579 authored by catch's avatar catch
Browse files

Issue #2160091 by alexpott, dawehner, damiankloip, swentel, sun, moshe...

Issue #2160091 by alexpott, dawehner, damiankloip, swentel, sun, moshe weitzman, xjm, joelpittet, charginghawk: drupal_rebuild() rebuilds container twice, since drupal_flush_all_caches() also rebuilds it
parent 65873ade
Loading
Loading
Loading
Loading
+26 −30
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\SortArray;
use Drupal\Core\Cache\Cache;
use Drupal\Core\DrupalKernel;
use Drupal\Core\StringTranslation\TranslatableMarkup;

/**
@@ -460,10 +461,11 @@ function show(&$element) {
}

/**
 * Flushes all persistent caches, resets all variables, and rebuilds all data structures.
 * Rebuilds the container, flushes all persistent caches, resets all variables, and rebuilds all data structures.
 *
 * At times, it is necessary to re-initialize the entire system to account for
 * changed or new code. This function:
 * - Rebuilds the container if $kernel is not passed in.
 * - Clears all persistent caches:
 *   - The bootstrap cache bin containing base system, module system, and theme
 *     system information.
@@ -483,6 +485,10 @@ function show(&$element) {
 *   - The 'active' status of fields is refreshed.
 * - Rebuilds the menu router.
 *
 * It's discouraged to call this during a regular page request.
 * If you call this function in tests, every code afterwards should use the new
 * container.
 *
 * This means the entire system is reset so all caches and static variables are
 * effectively empty. After that is guaranteed, information about the currently
 * active code is updated, and rebuild operations are successively called in
@@ -512,12 +518,19 @@ function show(&$element) {
 *   cache though.)
 * @todo Add a global lock to ensure that caches are not primed in concurrent
 *   requests.
 *
 * @param \Drupal\Core\DrupalKernel|array $kernel
 *   (optional) The Drupal Kernel. It is the caller's responsibility to rebuild
 *   the container if this is passed in. Sometimes drupal_flush_all_caches is
 *   used as a batch operation so $kernel will be an array, in this instance it
 *   will be treated as if it it NULL.
 */
function drupal_flush_all_caches() {
function drupal_flush_all_caches($kernel = NULL) {
  // This is executed based on old/previously known information if $kernel is
  // not passed in, which is sufficient, since new extensions cannot have any
  // primed caches yet.
  $module_handler = \Drupal::moduleHandler();
  // Flush all persistent caches.
  // This is executed based on old/previously known information, which is
  // sufficient, since new extensions cannot have any primed caches yet.
  $module_handler->invokeAll('cache_flush');
  foreach (Cache::getBins() as $service_id => $cache_backend) {
    $cache_backend->deleteAll();
@@ -531,43 +544,26 @@ function drupal_flush_all_caches() {
  // Reset all static caches.
  drupal_static_reset();

  // Invalidate the container.
  \Drupal::service('kernel')->invalidateContainer();

  // Wipe the Twig PHP Storage cache.
  \Drupal::service('twig')->invalidate();

  // Rebuild module and theme data.
  $module_data = \Drupal::service('extension.list.module')->reset()->getList();
  /** @var \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler */
  $theme_handler = \Drupal::service('theme_handler');
  $theme_handler->refreshInfo();
  // Rebuild theme data that is stored in state.
  \Drupal::service('theme_handler')->refreshInfo();
  // In case the active theme gets requested later in the same request we need
  // to reset the theme manager.
  \Drupal::theme()->resetActiveTheme();

  // Rebuild and reboot a new kernel. A simple DrupalKernel reboot is not
  // sufficient, since the list of enabled modules might have been adjusted
  // above due to changed code.
  $files = [];
  $modules = [];
  foreach ($module_data as $name => $extension) {
    if ($extension->status) {
      $files[$name] = $extension;
      $modules[$name] = $extension->weight;
  if (!$kernel instanceof DrupalKernel) {
    $kernel = \Drupal::service('kernel');
    $kernel->invalidateContainer();
    $kernel->rebuildContainer();
  }
  }
  $modules = module_config_sort($modules);
  \Drupal::service('kernel')->updateModules($modules, $files);
  // New container, new module handler.
  $module_handler = \Drupal::moduleHandler();

  // Ensure that all modules that are currently supposed to be enabled are
  // actually loaded.
  $module_handler->loadAll();
  // Rebuild module data that is stored in state.
  \Drupal::service('extension.list.module')->reset();

  // Rebuild all information based on new module data.
  $module_handler->invokeAll('rebuild');
  \Drupal::moduleHandler()->invokeAll('rebuild');

  // Clear all plugin caches.
  \Drupal::service('plugin.cache_clearer')->clearCachedDefinitions();
+3 −13
Original line number Diff line number Diff line
@@ -5,8 +5,6 @@
 * Miscellaneous functions.
 */

use Drupal\Core\PhpStorage\PhpStorageFactory;
use Drupal\Core\Cache\Cache;
use Drupal\Core\DrupalKernel;
use Symfony\Component\HttpFoundation\Request;

@@ -28,12 +26,11 @@ function drupal_rebuild($class_loader, Request $request) {
  restore_error_handler();
  restore_exception_handler();

  // Force kernel to rebuild php cache.
  PhpStorageFactory::get('twig')->deleteAll();

  // Invalidate the container.
  // Bootstrap up to where caches exist and clear them.
  $kernel = new DrupalKernel('prod', $class_loader);
  $kernel->setSitePath(DrupalKernel::findSitePath($request));
  $kernel->invalidateContainer();
  $kernel->boot();
  $kernel->preHandle($request);
  // Ensure our request includes the session if appropriate.
@@ -41,18 +38,11 @@ function drupal_rebuild($class_loader, Request $request) {
    $request->setSession($kernel->getContainer()->get('session'));
  }

  // Invalidate the container.
  $kernel->invalidateContainer();

  foreach (Cache::getBins() as $bin) {
    $bin->deleteAll();
  }
  drupal_flush_all_caches($kernel);

  // Disable recording of cached pages.
  \Drupal::service('page_cache_kill_switch')->trigger();

  drupal_flush_all_caches();

  // Restore Drupal's error and exception handlers.
  // @see \Drupal\Core\DrupalKernel::boot()
  set_error_handler('_drupal_error_handler');
+5 −0
Original line number Diff line number Diff line
name: 'Service Provider test'
type: module
description: 'Support module for service provider testing.'
package: Testing
version: VERSION
+6 −0
Original line number Diff line number Diff line
container_rebuild_test.module_path:
  path: '/container_rebuild_test/{module}/{function}'
  defaults:
    _controller: '\Drupal\container_rebuild_test\TestController::showModuleInfo'
  requirements:
    _access: 'TRUE'
+18 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\container_rebuild_test;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;

class ContainerRebuildTestServiceProvider implements ServiceModifierInterface {

  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container) {
    $count = $container->get('state')->get('container_rebuild_test.count', 0);
    $container->get('state')->set('container_rebuild_test.count', ++$count);
  }

}
Loading