diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index cea9627..af7b71b 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -19,6 +19,9 @@
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Template\Attribute;
+use Drupal\taxonomy\Entity\Vocabulary;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
+use Drupal\Core\Extension\Extension;
/**
* Implements hook_help().
@@ -572,3 +575,32 @@ function book_node_type_update(NodeTypeInterface $type) {
$config->save();
}
}
+
+/**
+ * Implements hook_system_info_alter().
+ *
+ * Prevents book module from being uninstalled whilst any book nodes exist
+ * or there are any book outline stored.
+ */
+function book_system_info_alter(&$info, Extension $file, $type) {
+ // It is not safe use the entity query service during maintenance mode.
+ if ($type == 'module' && !defined('MAINTENANCE_MODE') && $file->getName() == 'book') {
+ $factory = \Drupal::service('entity.query');
+ $nodes = $factory->get('node')
+ ->condition('type', 'book')
+ ->accessCheck(FALSE)
+ ->range(0, 1)
+ ->execute();
+ if (!empty($nodes)) {
+ $info['required'] = TRUE;
+ $info['explanation'] = t('To uninstall Book first delete all Book content.');
+ }
+ /** @var \Drupal\book\BookOutlineStorageInterface $outline_storage */
+ $outline_storage = \Drupal::service('book.outline_storage');
+ $books = $outline_storage->getBooks();
+ if (!empty($books)) {
+ $info['required'] = TRUE;
+ $info['explanation'] = t('To uninstall Book first delete all Book outlined nodes.');
+ }
+ }
+}
diff --git a/core/modules/book/config/install/node.type.book.yml b/core/modules/book/config/install/node.type.book.yml
index 172eaaf..3613038 100644
--- a/core/modules/book/config/install/node.type.book.yml
+++ b/core/modules/book/config/install/node.type.book.yml
@@ -7,3 +7,7 @@ display_submitted: true
preview_mode: 1
status: true
langcode: en
+dependencies:
+ enforced:
+ module:
+ - book