diff --git a/core/modules/book/book.module b/core/modules/book/book.module index 1fe04c8..f3737a0 100644 --- a/core/modules/book/book.module +++ b/core/modules/book/book.module @@ -205,11 +205,7 @@ function book_menu() { ); $items['node/%node/outline/remove'] = array( 'title' => 'Remove from outline', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('book_remove_form', 1), - 'access callback' => '_book_outline_remove_access', - 'access arguments' => array(1), - 'file' => 'book.pages.inc', + 'route_name' => 'book_remove', ); return $items; @@ -242,31 +238,6 @@ function _book_outline_access(EntityInterface $node) { } /** - * Access callback: Determines if the user can remove nodes from the outline. - * - * @param \Drupal\Core\Entity\EntityInterface $node - * The node to remove from the outline. - * - * @see book_menu() - */ -function _book_outline_remove_access(EntityInterface $node) { - return _book_node_is_removable($node) && _book_outline_access($node); -} - -/** - * Determines if a node can be removed from the book. - * - * A node can be removed from a book if it is actually in a book and it either - * is not a top-level page or is a top-level page with no children. - * - * @param \Drupal\Core\Entity\EntityInterface $node - * The node to remove from the outline. - */ -function _book_node_is_removable(EntityInterface $node) { - return (!empty($node->book['bid']) && (($node->book['bid'] != $node->nid) || !$node->book['has_children'])); -} - -/** * Implements hook_admin_paths(). */ function book_admin_paths() { diff --git a/core/modules/book/book.pages.inc b/core/modules/book/book.pages.inc index bc5ec53..cae2794 100644 --- a/core/modules/book/book.pages.inc +++ b/core/modules/book/book.pages.inc @@ -138,7 +138,7 @@ function book_outline_form($form, &$form_state, EntityInterface $node) { $form['remove'] = array( '#type' => 'submit', '#value' => t('Remove from book outline'), - '#access' => _book_node_is_removable($node), + '#access' => \Drupal::service('book.manager')->nodeIsRemovable($node), '#weight' => 20, '#submit' => array('book_remove_button_submit'), ); @@ -188,42 +188,3 @@ function book_outline_form_submit($form, &$form_state) { drupal_set_message(t('There was an error adding the post to the book.'), 'error'); } } - -/** - * Form constructor to confirm removal of a node from a book. - * - * @param \Drupal\Core\Entity\EntityInterface $node - * The node to delete. - * - * @see book_remove_form_submit() - * @see book_menu() - * @ingroup forms - */ -function book_remove_form($form, &$form_state, EntityInterface $node) { - $form['#node'] = $node; - $title = array('%title' => $node->label()); - - if ($node->book['has_children']) { - $description = t('%title has associated child pages, which will be relocated automatically to maintain their connection to the book. To recreate the hierarchy (as it was before removing this page), %title may be added again using the Outline tab, and each of its former child pages will need to be relocated manually.', $title); - } - else { - $description = t('%title may be added to hierarchy again using the Outline tab.', $title); - } - - return confirm_form($form, t('Are you sure you want to remove %title from the book hierarchy?', $title), 'node/' . $node->nid, $description, t('Remove')); -} - -/** - * Form submission handler for book_remove_form(). - */ -function book_remove_form_submit($form, &$form_state) { - $node = $form['#node']; - if (_book_node_is_removable($node)) { - menu_link_delete($node->book['mlid']); - db_delete('book') - ->condition('nid', $node->nid) - ->execute(); - drupal_set_message(t('The post has been removed from the book.')); - } - $form_state['redirect'] = 'node/' . $node->nid; -} diff --git a/core/modules/book/book.routing.yml b/core/modules/book/book.routing.yml index 6c8b010..7406250 100644 --- a/core/modules/book/book.routing.yml +++ b/core/modules/book/book.routing.yml @@ -18,3 +18,14 @@ book_settings: _form: 'Drupal\book\BookSettingsForm' requirements: _permission: 'administer site configuration' + +book_remove: + pattern: 'node/{node}/outline/remove' + defaults: + _form: '\Drupal\book\Form\BookRemoveForm' + options: + _access_checks: 'ALL' + requirements: + _permission: 'administer book outlines' + _entity_access: 'node.view' + _book_node_is_removable: 'TRUE' diff --git a/core/modules/book/book.services.yml b/core/modules/book/book.services.yml index 9d8c140..d905eb7 100644 --- a/core/modules/book/book.services.yml +++ b/core/modules/book/book.services.yml @@ -2,3 +2,8 @@ services: book.manager: class: Drupal\book\BookManager arguments: ['@database', '@plugin.manager.entity'] + access_check.book.removable: + class: Drupal\book\Access\BookNodeIsRemovableAccessCheck + arguments: ['@book.manager'] + tags: + - { name: access_check } diff --git a/core/modules/book/lib/Drupal/book/Access/BookNodeIsRemovableAccessCheck.php b/core/modules/book/lib/Drupal/book/Access/BookNodeIsRemovableAccessCheck.php new file mode 100644 index 0000000..8c88974 --- /dev/null +++ b/core/modules/book/lib/Drupal/book/Access/BookNodeIsRemovableAccessCheck.php @@ -0,0 +1,56 @@ +bookManager = $book_manager; + } + + /** + * {@inheritdoc} + */ + public function applies(Route $route) { + return array_key_exists('_book_node_is_removable', $route->getRequirements()); + } + + /** + * {@inheritdoc} + */ + public function access(Route $route, Request $request) { + $node = $request->attributes->get('node'); + if (!empty($node)) { + $removable = ($this->bookManager->nodeIsRemovable($node) ? 'TRUE' : 'FALSE'); + if ($removable != strtoupper($route->getRequirement('_book_node_is_removable'))) { + return static::KILL; + } + } + } +} diff --git a/core/modules/book/lib/Drupal/book/BookManager.php b/core/modules/book/lib/Drupal/book/BookManager.php index b037429..ec27471 100644 --- a/core/modules/book/lib/Drupal/book/BookManager.php +++ b/core/modules/book/lib/Drupal/book/BookManager.php @@ -8,6 +8,7 @@ use Drupal\Core\Database\Connection; use Drupal\Core\Entity\EntityManager; +use Drupal\Node\NodeInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -38,10 +39,16 @@ class BookManager { /** * Constructs a BookManager object. + * + * @param \Drupal\Core\Database\Connection $database + * Database Service. + * + * @param \Drupal\Core\Entity\EntityManager $entity_manager + * Entity Manager Service. */ - public function __construct(Connection $database, EntityManager $entityManager) { + public function __construct(Connection $database, EntityManager $entity_manager) { $this->database = $database; - $this->entityManager = $entityManager; + $this->entityManager = $entity_manager; } /** @@ -50,7 +57,7 @@ public function __construct(Connection $database, EntityManager $entityManager) * This list may be used for generating a list of all the books, or for building * the options for a form select. * - * @return + * @return array * An array of all books. */ public function getAllBooks() { @@ -94,4 +101,33 @@ protected function loadBooks() { } } + /** + * Determines if a node can be removed from the book. + * + * A node can be removed from a book if it is actually in a book and it either + * is not a top-level page or is a top-level page with no children. + * + * @param \Drupal\Node\NodeInterface $node + * The node to remove from the outline. + * + * @return bool + * TRUE if node is in a book or a top-level page with no children, FALSE + * otherwise. + */ + public function nodeIsRemovable(NodeInterface $node) { + return (!empty($node->book['bid']) && (($node->book['bid'] != $node->nid) || !$node->book['has_children'])); + } + + /** + * Deletes node's entry form book table. + * + * @param int $nid + * The nid to delete. + */ + public function deleteBook($nid) { + $this->database->delete('book') + ->condition('nid', $nid) + ->execute(); + } + } diff --git a/core/modules/book/lib/Drupal/book/Form/BookRemoveForm.php b/core/modules/book/lib/Drupal/book/Form/BookRemoveForm.php new file mode 100644 index 0000000..f6e831d --- /dev/null +++ b/core/modules/book/lib/Drupal/book/Form/BookRemoveForm.php @@ -0,0 +1,142 @@ +get('book.manager'), $container->get('plugin.manager.entity')->getStorageController('menu_link')); + } + + /** + * Constructs a BookRemoveForm object. + * + * @param \Drupal\book\BookManager $book_manager + * Book Manager Service. + * + * @param \Drupal\menu_link\MenuLinkStorageControllerInterface $menu_link_storage + * Menu Link Storage Controller. + */ + public function __construct(BookManager $book_manager, MenuLinkStorageControllerInterface $menu_link_storage) { + $this->bookManager = $book_manager; + $this->menuLinkStorage = $menu_link_storage; + } + + /** + * {@inheritdoc} + */ + public function getFormID() { + return 'book_remove_form'; + } + + /** + * {@inheritdoc} + */ + public function getCancelPath() { + $uri = $this->node->uri(); + return $uri['path']; + } + + /** + * {@inheritdoc} + */ + public function getQuestion() { + return t('Are you sure you want to remove %title from the book hierarchy?', array('%title' => $this->node->label())); + } + + /** + * {@inheritdoc} + */ + public function getDescription() { + $t_title = array('%title' => $this->node->label()); + if ($this->node->book['has_children']) { + $description = t('%title has associated child pages, which will be relocated automatically to maintain their connection to the book. To recreate the hierarchy (as it was before removing this page), %title may be added again using the Outline tab, and each of its former child pages will need to be relocated manually.', $t_title); + } + else { + $description = t('%title may be added to hierarchy again using the Outline tab.', $t_title); + } + return $description; + } + + /** + * {@inheritdoc} + */ + public function getConfirmText() { + return t('Remove'); + } + + /** + * Form constructor. + * + * @param array $form + * An associative array containing the structure of the form. + * @param array $form_state + * An associative array containing the current state of the form. + * @param \Drupal\Node\NodeInterface $node + * The node to delete. + * @param Symfony\Component\HttpFoundation\Request $request + * The request object. + * + * @return array + * The form structure. + */ + public function buildForm(array $form, array &$form_state, NodeInterface $node = NULL, Request $request = NULL) { + $this->node = $node; + return parent::buildForm($form, $form_state, $request); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + if ($this->bookManager->nodeIsRemovable($this->node)) { + $menu_links = $this->menuLinkStorage->load(array($this->node->book['mlid'])); + $this->menuLinkStorage->delete($menu_links); + $this->bookManager->deleteBook($this->node->id()); + drupal_set_message(t('The post has been removed from the book.')); + } + $uri = $this->node->uri(); + $form_state['redirect'] = $uri['path']; + } + +}