diff --git a/core/modules/block/src/Tests/BlockConfigSchemaTest.php b/core/modules/block/src/Tests/BlockConfigSchemaTest.php index ccd0a73..2a70ecf 100644 --- a/core/modules/block/src/Tests/BlockConfigSchemaTest.php +++ b/core/modules/block/src/Tests/BlockConfigSchemaTest.php @@ -64,6 +64,7 @@ protected function setUp() { $this->installEntitySchema('block_content'); $this->installEntitySchema('taxonomy_term'); $this->installEntitySchema('node'); + $this->installSchema('book', array('book')); } /** diff --git a/core/modules/book/book.module b/core/modules/book/book.module index 7f7830c..c5e7f59 100644 --- a/core/modules/book/book.module +++ b/core/modules/book/book.module @@ -19,6 +19,7 @@ use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Template\Attribute; +use Drupal\Core\Extension\Extension; /** * Implements hook_help(). @@ -572,3 +573,36 @@ 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') { + if (!\Drupal::hasService('book.outline_storage')) { + $a = 1; + } + if (\Drupal::service('book.outline_storage')->hasBooks()) { + $info['required'] = TRUE; + $info['explanation'] = t('To uninstall Book, delete all content that is part of a book.'); + } + else { + // The book node type is provided by the Book module. Prevent uninstall if + // there are any node's of that type. + $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, delete all content that has the Book content type.'); + } + } + } +} diff --git a/core/modules/book/config/install/node.type.book.yml b/core/modules/book/config/install/node.type.book.yml index 172eaaf..3bb1dbb 100644 --- a/core/modules/book/config/install/node.type.book.yml +++ b/core/modules/book/config/install/node.type.book.yml @@ -1,9 +1,14 @@ -type: book +langcode: en +status: true +dependencies: + enforced: + module: + - book name: 'Book page' +type: book description: 'Books have a built-in hierarchical navigation. Use for handbooks or tutorials.' help: '' new_revision: false -display_submitted: true preview_mode: 1 -status: true -langcode: en +display_submitted: true +third_party_settings: { } diff --git a/core/modules/book/src/BookOutlineStorage.php b/core/modules/book/src/BookOutlineStorage.php index cfc281a..8e8271d 100644 --- a/core/modules/book/src/BookOutlineStorage.php +++ b/core/modules/book/src/BookOutlineStorage.php @@ -38,6 +38,15 @@ public function getBooks() { /** * {@inheritdoc} */ + public function hasBooks() { + return (bool) $this->connection + ->query('SELECT count(bid) FROM {book}') + ->fetchField(); + } + + /** + * {@inheritdoc} + */ public function loadMultiple($nids) { $query = $this->connection->select('book', 'b', array('fetch' => \PDO::FETCH_ASSOC)); $query->fields('b'); diff --git a/core/modules/book/src/BookOutlineStorageInterface.php b/core/modules/book/src/BookOutlineStorageInterface.php index 8a27592..e08fab6 100644 --- a/core/modules/book/src/BookOutlineStorageInterface.php +++ b/core/modules/book/src/BookOutlineStorageInterface.php @@ -21,6 +21,14 @@ public function getBooks(); /** + * Checks if there are any books. + * + * @return bool + * TRUE if there are books, FALSE if not. + */ + public function hasBooks(); + + /** * Loads books. * * @param array $nids diff --git a/core/modules/config/src/Tests/ConfigImportAllTest.php b/core/modules/config/src/Tests/ConfigImportAllTest.php index bc801c3..4900f98 100644 --- a/core/modules/config/src/Tests/ConfigImportAllTest.php +++ b/core/modules/config/src/Tests/ConfigImportAllTest.php @@ -110,6 +110,8 @@ public function testInstallUninstall() { // Import the configuration thereby re-installing all the modules. $this->drupalPostForm('admin/config/development/configuration', array(), t('Import all')); + // Modules have been installed that have services. + $this->rebuildContainer(); // Check that there are no errors. $this->assertIdentical($this->configImporter()->getErrors(), array()); diff --git a/core/modules/node/src/Tests/NodeTypeTest.php b/core/modules/node/src/Tests/NodeTypeTest.php index 23b692d..dde6bf9 100644 --- a/core/modules/node/src/Tests/NodeTypeTest.php +++ b/core/modules/node/src/Tests/NodeTypeTest.php @@ -123,35 +123,6 @@ function testNodeTypeEditing() { } /** - * Tests that node types correctly handles their locking. - */ - function testNodeTypeStatus() { - // Enable all core node modules, and all types should be active. - $this->container->get('module_handler')->install(array('book'), FALSE); - $types = node_type_get_types(); - foreach (array('book', 'article', 'page') as $type) { - $this->assertTrue(isset($types[$type]), format_string('%type is found in node types.', array('%type' => $type))); - $this->assertFalse($types[$type]->isLocked(), format_string('%type type is not locked.', array('%type' => $type))); - } - - // Disable book module and the respective type should still be active, since - // it is not provided by shipped configuration entity. - $this->container->get('module_handler')->uninstall(array('book'), FALSE); - $types = node_type_get_types(); - $this->assertFalse($types['book']->isLocked(), "Book module's node type still active."); - $this->assertFalse($types['article']->isLocked(), 'Article node type still active.'); - $this->assertFalse($types['page']->isLocked(), 'Basic page node type still active.'); - - // Re-install the modules and verify that the types are active again. - $this->container->get('module_handler')->install(array('book'), FALSE); - $types = node_type_get_types(); - foreach (array('book', 'article', 'page') as $type) { - $this->assertTrue(isset($types[$type]), format_string('%type is found in node types.', array('%type' => $type))); - $this->assertFalse($types[$type]->isLocked(), format_string('%type type is not locked.', array('%type' => $type))); - } - } - - /** * Tests deleting a content type that still has content. */ function testNodeTypeDeletion() {