diff --git a/core/modules/system/system.module b/core/modules/system/system.module index f3b65a2..6826135 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -5,20 +5,21 @@ * Configuration system that lets administrators modify the workings of the site. */ +use Drupal\Component\Plugin\Exception\PluginNotFoundException; +use Drupal\Core\Block\BlockPluginInterface; use Drupal\Core\Cache\Cache; +use Drupal\Core\Entity\Query\QueryException; use Drupal\Core\Extension\Extension; use Drupal\Core\Extension\ExtensionDiscovery; -use Drupal\Core\Form\FormState; use Drupal\Core\Form\FormStateInterface; -use Drupal\Core\Routing\RouteMatchInterface; -use Drupal\Core\StringTranslation\TranslationWrapper; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Menu\MenuTreeParameters; +use Drupal\Core\Routing\RouteMatchInterface; +use Drupal\Core\StringTranslation\TranslationWrapper; use Drupal\Core\Url; -use Drupal\Core\Block\BlockPluginInterface; use Drupal\user\UserInterface; -use Symfony\Component\HttpFoundation\RedirectResponse; use GuzzleHttp\Exception\RequestException; +use Symfony\Component\HttpFoundation\RedirectResponse; /** * New users will be set to the default time zone at registration. @@ -1032,11 +1033,55 @@ function system_sort_themes($a, $b) { * Implements hook_system_info_alter(). */ function system_system_info_alter(&$info, Extension $file, $type) { - // Remove page-top and page-bottom from the blocks UI since they are reserved for - // modules to populate from outside the blocks system. - if ($type == 'theme') { - $info['regions_hidden'][] = 'page_top'; - $info['regions_hidden'][] = 'page_bottom'; + switch ($type) { + case 'theme': + // Remove page-top and page-bottom from the blocks UI since they are + // reserved for modules to populate from outside the blocks system. + $info['regions_hidden'][] = 'page_top'; + $info['regions_hidden'][] = 'page_bottom'; + break; + + case 'module': + // @todo Unify this with field_system_info_alter() once purging is + // supported for any field. See https://www.drupal.org/node/2282119. + $module_name = $file->getName(); + if ($module_name != 'field') { + $entity_manager = \Drupal::entityManager(); + foreach ($entity_manager->getDefinitions() as $entity_type_id => $entity_type) { + try { + // We skip entity-defining modules, otherwise deleting all entities + // would be required before being able to uninstall them. + if ($entity_type->getProvider() != $module_name && $entity_type->isFieldable()) { + try { + $query = \Drupal::entityQuery($entity_type_id); + } + catch (QueryException $e) { + // If an entity type can't be queried, treat it has having no + // data for purposes of allowing its fields' field type modules + // to be uninstalled. + // @todo Require all storage handlers to support querying: + // https://www.drupal.org/node/2337753. + $query = NULL; + } + if ($query && $query->count()->execute()) { + foreach ($entity_manager->getFieldStorageDefinitions($entity_type_id) as $storage_definition) { + if ($storage_definition->getProvider() == $module_name) { + $info['required'] = TRUE; + $info['explanation'] = t('Fields type(s) in use'); + break; + } + } + } + } + } + catch (PluginNotFoundException $e) { + // This may happen if the current module is being installed. In this + // case we can safely ignore it, as we are interested in blocking + // module uninstallation. + } + } + } + break; } }