Change record status: 
Project: 
Introduced in branch: 
8.0.x
Description: 

ModuleUninstallValidatorInterface was added to validate the readiness of a module to be uninstalled. "Validate" in this context means determining if the module can be safely uninstalled without side effects based on the system state.

To use it, an uninstall validator class must implement the interface and in its service definition, be tagged a 'module_install.uninstall_validator'.

An example service definition:

  content_uninstall_validator:
    class: Drupal\Core\Entity\ContentUninstallValidator
    tags:
      - { name: module_install.uninstall_validator }
    arguments: ['@entity.manager', '@string_translation']

The interface:

interface ModuleUninstallValidatorInterface {

  /**
   * Determines the reasons a module can not be uninstalled.
   *
   * @param string $module
   *   A module name.
   *
   * @return string[]
   *   An array of reasons the module can not be uninstalled, empty if it can.
   */
  public function validate($module);
}

An example implementation:

class ContentUninstallValidator implements ModuleUninstallValidatorInterface {
  use StringTranslationTrait;

  /**
   * Constructs a new ContentUninstallValidator.
   *
   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
   *   The entity manager.
   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
   *   The string translation service.
   */
  public function __construct(EntityManagerInterface $entity_manager, TranslationInterface $string_translation) {
    $this->entityManager = $entity_manager;
    $this->stringTranslation = $string_translation;
  }

  /**
   * {@inheritdoc}
   */
  public function validate($module) {
    $entity_types = $this->entityManager->getDefinitions();
    $reasons = array();
    foreach ($entity_types as $entity_type) {
      if ($module == $entity_type->getProvider() && $entity_type instanceof ContentEntityTypeInterface && $this->entityManager->getStorage($entity_type->id())->hasData()) {
        $reasons[] = $this->t('There is content for the entity type: @entity_type', array('@entity_type' => $entity_type->getLabel()));
      }
    }
    return $reasons;
  }

}
Impacts: 
Module developers