Unverified Commit 4ff38482 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3066801 by catch, WidgetsBurritos, pobster, jungle, tim.plunkett, xjm,...

Issue #3066801 by catch, WidgetsBurritos, pobster, jungle, tim.plunkett, xjm, dww, alexpott, webchick, benjifisher, longwave, worldlinemine, lauriii, Berdir: Add hook_removed_post_updates()
parent c5b2a892
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -295,10 +295,13 @@ public function install(array $module_list, $enable_dependencies = TRUE) {
        }
        drupal_set_installed_schema_version($module, $version);

        // Ensure that all post_update functions are registered already.
        // Ensure that all post_update functions are registered already. This
        // should include existing post-updates, as well as any specified as
        // having been previously removed, to ensure that newly installed and
        // updated sites have the same entries in the registry.
        /** @var \Drupal\Core\Update\UpdateRegistry $post_update_registry */
        $post_update_registry = \Drupal::service('update.post_update_registry');
        $post_update_registry->registerInvokedUpdates($post_update_registry->getModuleUpdateFunctions($module));
        $post_update_registry->registerInvokedUpdates(array_merge($post_update_registry->getModuleUpdateFunctions($module), array_keys($post_update_registry->getRemovedPostUpdates($module))));

        // Record the fact that it was installed.
        $modules_installed[] = $module;
+25 −0
Original line number Diff line number Diff line
@@ -745,6 +745,7 @@ function hook_update_N(&$sandbox) {
 * @ingroup update_api
 *
 * @see hook_update_N()
 * @see hook_removed_post_updates()
 */
function hook_post_update_NAME(&$sandbox) {
  // Example of updating some content.
@@ -763,6 +764,30 @@ function hook_post_update_NAME(&$sandbox) {
  return $result;
}

/**
 * Return an array of removed hook_post_update_NAME() function names.
 *
 * This should be used to indicate post-update functions that have existed in
 * some previous version of the module, but are no longer available.
 *
 * This implementation has to be placed in a MODULE.post_update.php file.
 *
 * @return string[]
 *   An array where the keys are removed post-update function names, and the
 *   values are the first stable version in which the update was removed.
 *
 * @ingroup update_api
 *
 * @see hook_post_update_NAME()
 */
function hook_removed_post_updates() {
  return [
    'mymodule_post_update_foo' => '8.x-2.0',
    'mymodule_post_update_bar' => '8.x-3.0',
    'mymodule_post_update_baz' => '8.x-3.0',
  ];
}

/**
 * Return an array of information about module update dependencies.
 *
+12 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Core\Update;

/**
 * An exception thrown for removed post-update functions.
 *
 * Occurs when a module defines hook_post_update_NAME() implementations
 * that are listed as removed in hook_removed_post_updates().
 */
class RemovedPostUpdateNameException extends \LogicException {
}
+23 −2
Original line number Diff line number Diff line
@@ -86,6 +86,21 @@ public function __construct($root, $site_path, array $enabled_modules, KeyValueS
    $this->includeTests = $include_tests;
  }

  /**
   * Gets removed hook_post_update_NAME() implementations for a module.
   *
   * @return string[]
   *   A list of post-update functions that have been removed.
   */
  public function getRemovedPostUpdates($module) {
    $this->scanExtensionsAndLoadUpdateFiles();
    $function = "{$module}_removed_post_updates";
    if (function_exists($function)) {
      return $function();
    }
    return [];
  }

  /**
   * Gets all available update functions.
   *
@@ -102,11 +117,17 @@ protected function getAvailableUpdateFunctions() {
      // module updates.
      if (preg_match($regexp, $function, $matches)) {
        if (in_array($matches['module'], $this->enabledModules)) {
          $updates[] = $matches['module'] . '_' . $this->updateType . '_' . $matches['name'];
          $function_name = $matches['module'] . '_' . $this->updateType . '_' . $matches['name'];
          if ($this->updateType === 'post_update') {
            $removed = array_keys($this->getRemovedPostUpdates($matches['module']));
            if (array_search($function_name, $removed) !== FALSE) {
              throw new RemovedPostUpdateNameException(sprintf('The following update is specified as removed in hook_removed_post_updates() but still exists in the code base: %s', $function_name));
            }
          }
          $updates[] = $function_name;
        }
      }
    }

    // Ensure that the update order is deterministic.
    sort($updates);
    return $updates;
+30 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
use Drupal\Core\Site\Settings;
use Drupal\Core\StreamWrapper\PrivateStream;
use Drupal\Core\StreamWrapper\PublicStream;
use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Symfony\Component\HttpFoundation\Request;
@@ -1135,6 +1136,35 @@ function system_requirements($phase) {
        ];
      }
    }
    // Also check post-updates. Only do this if we're not already showing an
    // error for hook_update_N().
    if (empty($module_list)) {
      $existing_updates = \Drupal::service('keyvalue')->get('post_update')->get('existing_updates', []);
      $post_update_registry = \Drupal::service('update.post_update_registry');
      $modules = \Drupal::moduleHandler()->getModuleList();
      $module_extension_list = \Drupal::service('extension.list.module');
      foreach ($modules as $module => $extension) {
        $module_info = $module_extension_list->get($module);
        $removed_post_updates = $post_update_registry->getRemovedPostUpdates($module);
        if ($missing_updates = array_diff(array_keys($removed_post_updates), $existing_updates)) {
          $versions = array_unique(array_intersect_key($removed_post_updates, array_flip($missing_updates)));
          $description = new PluralTranslatableMarkup(count($versions),
            'The installed version of the %module module is too old to update. Update to a version prior to @versions first (missing updates: @missing_updates).',
            'The installed version of the %module module is too old to update. Update first to a version prior to all of the following: @versions (missing updates: @missing_updates).',
            [
              '%module' => $module_info->info['name'],
              '@missing_updates' => implode(', ', $missing_updates),
              '@versions' => implode(', ', $versions),
            ]
          );
          $requirements[$module . '_post_update_removed'] = [
            'title' => t('Missing updates for: @module', ['@module' => $module_info->info['name']]),
            'description' => $description,
            'severity' => REQUIREMENT_ERROR,
          ];
        }
      }
    }
  }

  return $requirements;
Loading