diff --git a/core/modules/book/book.module b/core/modules/book/book.module index 5f6b92f..0fe58ed 100644 --- a/core/modules/book/book.module +++ b/core/modules/book/book.module @@ -246,20 +246,8 @@ function _book_outline_access(EntityInterface $node) { * @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'])); + return Drupal::service('book.manager')->bookNodeIsRemovable($node) + && _book_outline_access($node); } /** @@ -298,6 +286,9 @@ function book_get_books() { * @see book_pick_book_nojs_submit() */ function book_form_node_form_alter(&$form, &$form_state, $form_id) { + // Get BookManager service + $book_manager = Drupal::service('book.manager'); + $node = $form_state['controller']->getEntity(); $access = user_access('administer book outlines'); if (!$access) { @@ -306,9 +297,8 @@ function book_form_node_form_alter(&$form, &$form_state, $form_id) { $access = TRUE; } } - if ($access) { - _book_add_form_elements($form, $form_state, $node); + $book_manager->bookAddFormElements($form, $form_state, $node); // Since the "Book" dropdown can't trigger a form submission when // JavaScript is disabled, add a submit button to do that. book.admin.css hides // this button when JavaScript is enabled. @@ -328,7 +318,8 @@ function book_form_node_form_alter(&$form, &$form_state, $form_id) { * Implements hook_form_BASE_FORM_ID_alter() for the book_outline form. */ function book_form_book_outline_alter(&$form, &$form_state, $form_id) { - $node = $form_state['build_info']['args'][0]; + // Dynamically set title + $node = reset($form_state['build_info']['args']); drupal_set_title($node->label()); } @@ -404,91 +395,6 @@ function _book_parent_select($book_link) { } /** - * Builds the common elements of the book form for the node and outline forms. - * - * @param \Drupal\Core\Entity\EntityInterface $node - * The node whose form is being viewed. - */ -function _book_add_form_elements(&$form, &$form_state, EntityInterface $node) { - // If the form is being processed during the Ajax callback of our book bid - // dropdown, then $form_state will hold the value that was selected. - if (isset($form_state['values']['book'])) { - $node->book = $form_state['values']['book']; - } - $form['book'] = array( - '#type' => 'details', - '#title' => t('Book outline'), - '#weight' => 10, - '#collapsed' => TRUE, - '#group' => 'advanced', - '#attributes' => array( - 'class' => array('book-outline-form'), - ), - '#attached' => array( - 'library' => array(array('book', 'drupal.book')), - ), - '#tree' => TRUE, - ); - foreach (array('menu_name', 'mlid', 'nid', 'router_path', 'has_children', 'options', 'module', 'original_bid', 'parent_depth_limit') as $key) { - $form['book'][$key] = array( - '#type' => 'value', - '#value' => $node->book[$key], - ); - } - - $form['book']['plid'] = _book_parent_select($node->book); - - // @see _book_admin_table_tree(). The weight may be larger than 15. - $form['book']['weight'] = array( - '#type' => 'weight', - '#title' => t('Weight'), - '#default_value' => $node->book['weight'], - '#delta' => max(15, abs($node->book['weight'])), - '#weight' => 5, - '#description' => t('Pages at a given level are ordered first by weight and then by title.'), - ); - $options = array(); - $nid = isset($node->nid) ? $node->nid : 'new'; - - if (isset($node->nid) && ($nid == $node->book['original_bid']) && ($node->book['parent_depth_limit'] == 0)) { - // This is the top level node in a maximum depth book and thus cannot be moved. - $options[$node->nid] = $node->label(); - } - else { - foreach (book_get_books() as $book) { - $options[$book['nid']] = $book['title']; - } - } - - if (user_access('create new books') && ($nid == 'new' || ($nid != $node->book['original_bid']))) { - // The node can become a new book, if it is not one already. - $options = array($nid => t('- Create a new book -')) + $options; - } - if (!$node->book['mlid']) { - // The node is not currently in the hierarchy. - $options = array(0 => t('- None -')) + $options; - } - - // Add a drop-down to select the destination book. - $form['book']['bid'] = array( - '#type' => 'select', - '#title' => t('Book'), - '#default_value' => $node->book['bid'], - '#options' => $options, - '#access' => (bool) $options, - '#description' => t('Your page will be a part of the selected book.'), - '#weight' => -5, - '#attributes' => array('class' => array('book-title-select')), - '#ajax' => array( - 'callback' => 'book_form_update', - 'wrapper' => 'edit-book-plid-wrapper', - 'effect' => 'fade', - 'speed' => 'fast', - ), - ); -} - -/** * Renders a new parent page select element when the book selection changes. * * This function is called via Ajax when the selected book is changed on a node @@ -874,6 +780,9 @@ function book_node_predelete(EntityInterface $node) { * Implements hook_node_prepare(). */ function book_node_prepare(EntityInterface $node) { + // Get BookManager service + $book_manager = Drupal::service('book.manager'); + // Prepare defaults for the add/edit form. if (empty($node->book) && (user_access('add content to books') || user_access('administer book outlines'))) { $node->book = array(); @@ -889,7 +798,8 @@ function book_node_prepare(EntityInterface $node) { } } // Set defaults. - $node->book += _book_link_defaults(!empty($node->nid) ? $node->nid : 'new'); + $node_ref = !empty($node->nid) ? $node->nid : 'new'; + $node->book += $book_manager->bookLinkDefaults($node_ref); } else { if (isset($node->book['bid']) && !isset($node->book['original_bid'])) { @@ -898,24 +808,11 @@ function book_node_prepare(EntityInterface $node) { } // Find the depth limit for the parent select. if (isset($node->book['bid']) && !isset($node->book['parent_depth_limit'])) { - $node->book['parent_depth_limit'] = _book_parent_depth_limit($node->book); + $node->book['parent_depth_limit'] = $book_manager->bookParentDepthLimit($node->book); } } /** - * Finds the depth limit for items in the parent select. - * - * @param $book_link - * A fully loaded menu link that is part of the book hierarchy. - * - * @return - * The depth limit for items in the parent select. - */ -function _book_parent_depth_limit($book_link) { - return MENU_MAX_DEPTH - 1 - (($book_link['mlid'] && $book_link['has_children']) ? entity_get_controller('menu_link')->findChildrenRelativeDepth($book_link) : 0); -} - -/** * Implements hook_form_FORM_ID_alter() for node_delete_confirm(). * * Alters the confirm form for a single node deletion. @@ -934,19 +831,6 @@ function book_form_node_delete_confirm_alter(&$form, $form_state) { } /** - * Returns an array with default values for a book page's menu link. - * - * @param $nid - * The ID of the node whose menu link is being created. - * - * @return - * The default values for the menu link. - */ -function _book_link_defaults($nid) { - return array('original_bid' => 0, 'menu_name' => '', 'nid' => $nid, 'bid' => 0, 'router_path' => 'node/%', 'plid' => 0, 'mlid' => 0, 'has_children' => 0, 'weight' => 0, 'module' => 'book', 'options' => array()); -} - - /** * Implements hook_preprocess_HOOK() for block.html.twig. */ function book_preprocess_block(&$variables) { diff --git a/core/modules/book/book.pages.inc b/core/modules/book/book.pages.inc index c4a90e2..9486786 100644 --- a/core/modules/book/book.pages.inc +++ b/core/modules/book/book.pages.inc @@ -123,7 +123,7 @@ function book_remove_form($form, &$form_state, EntityInterface $node) { */ function book_remove_form_submit($form, &$form_state) { $node = $form['#node']; - if (_book_node_is_removable($node)) { + if (Drupal::service('book.manager')->bookNodeIsRemovable($node)) { menu_link_delete($node->book['mlid']); db_delete('book') ->condition('nid', $node->nid) diff --git a/core/modules/book/lib/Drupal/book/BookManager.php b/core/modules/book/lib/Drupal/book/BookManager.php index b037429..e093f49 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\Core\Entity\EntityInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -94,4 +95,129 @@ protected function loadBooks() { } } + /** + * Returns an array with default values for a book page's menu link. + * + * @param $nid + * The ID of the node whose menu link is being created. + * + * @return + * The default values for the menu link. + */ + public function bookLinkDefaults($nid) { + return array('original_bid' => 0, 'menu_name' => '', 'nid' => $nid, + 'bid' => 0, 'router_path' => 'node/%', 'plid' => 0, 'mlid' => 0, + 'has_children' => 0, 'weight' => 0, 'module' => 'book', + 'options' => array()); + } + + /** + * Finds the depth limit for items in the parent select. + * + * @param $book_link + * A fully loaded menu link that is part of the book hierarchy. + * + * @return + * The depth limit for items in the parent select. + */ + public function bookParentDepthLimit($book_link) { + return MENU_MAX_DEPTH - 1 - (($book_link['mlid'] && $book_link['has_children']) ? entity_get_controller('menu_link')->findChildrenRelativeDepth($book_link) : 0); + } + + /** + * Builds the common elements of the book form for the node and outline forms. + * + * @param \Drupal\Core\Entity\EntityInterface $node + * The node whose form is being viewed. + */ + public function bookAddFormElements(&$form, &$form_state, EntityInterface $node) { + // If the form is being processed during the Ajax callback of our book bid + // dropdown, then $form_state will hold the value that was selected. + if (isset($form_state['values']['book'])) { + $node->book = $form_state['values']['book']; + } + $form['book'] = array( + '#type' => 'details', + '#title' => t('Book outline'), + '#weight' => 10, + '#collapsed' => TRUE, + '#group' => 'advanced', + '#attributes' => array( + 'class' => array('book-outline-form'), + ), + '#attached' => array( + 'library' => array(array('book', 'drupal.book')), + ), + '#tree' => TRUE, + ); + foreach (array('menu_name', 'mlid', 'nid', 'router_path', 'has_children', 'options', 'module', 'original_bid', 'parent_depth_limit') as $key) { + $form['book'][$key] = array( + '#type' => 'value', + '#value' => $node->book[$key], + ); + } + + $form['book']['plid'] = _book_parent_select($node->book); + + // @see _book_admin_table_tree(). The weight may be larger than 15. + $form['book']['weight'] = array( + '#type' => 'weight', + '#title' => t('Weight'), + '#default_value' => $node->book['weight'], + '#delta' => max(15, abs($node->book['weight'])), + '#weight' => 5, + '#description' => t('Pages at a given level are ordered first by weight and then by title.'), + ); + $options = array(); + $nid = isset($node->nid) ? $node->nid : 'new'; + if (isset($node->nid) && ($nid == $node->book['original_bid']) && ($node->book['parent_depth_limit'] == 0)) { + // This is the top level node in a maximum depth book and thus cannot be moved. + $options[$node->nid] = $node->label(); + } + else { + foreach (book_get_books() as $book) { + $options[$book['nid']] = $book['title']; + } + } + + if (user_access('create new books') && ($nid == 'new' || ($nid != $node->book['original_bid']))) { + // The node can become a new book, if it is not one already. + $options = array($nid => t('- Create a new book -')) + $options; + } + if (!$node->book['mlid']) { + // The node is not currently in the hierarchy. + $options = array(0 => t('- None -')) + $options; + } + + // Add a drop-down to select the destination book. + $form['book']['bid'] = array( + '#type' => 'select', + '#title' => t('Book'), + '#default_value' => $node->book['bid'], + '#options' => $options, + '#access' => (bool) $options, + '#description' => t('Your page will be a part of the selected book.'), + '#weight' => -5, + '#attributes' => array('class' => array('book-title-select')), + '#ajax' => array( + 'callback' => 'book_form_update', + 'wrapper' => 'edit-book-plid-wrapper', + 'effect' => 'fade', + 'speed' => 'fast', + ), + ); + } + + /** + * 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. + */ + public function bookNodeIsRemovable(EntityInterface $node) { + return (!empty($node->book['bid']) && (($node->book['bid'] != $node->nid) || !$node->book['has_children'])); + } } diff --git a/core/modules/book/lib/Drupal/book/Form/BookOutlineForm.php b/core/modules/book/lib/Drupal/book/Form/BookOutlineForm.php index 802bc2e..9cbfcfa 100644 --- a/core/modules/book/lib/Drupal/book/Form/BookOutlineForm.php +++ b/core/modules/book/lib/Drupal/book/Form/BookOutlineForm.php @@ -10,13 +10,26 @@ use Drupal\Core\ControllerInterface; use Drupal\Core\Form\FormInterface; use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\book\BookManager; +use Drupal\Core\Entity\EntityBCDecorator; /** * Displays the book outline form. */ class BookOutlineForm implements ControllerInterface, FormInterface { - protected $database; + /** + * BookManager service + * @var Drupal\book\BookManager + */ + protected $bookManager; + + /** + * Constructs a BookOutlineForm object. + */ + public function __construct(BookManager $bookManager) { + $this->bookManager = $bookManager; + } /** * This method lets us inject the services this class needs. @@ -25,7 +38,7 @@ class BookOutlineForm implements ControllerInterface, FormInterface { * are needed will vary by the controller. */ public static function create(ContainerInterface $container) { - return new static($container->get('database')); + return new static($container->get('book.manager')); } /** @@ -38,10 +51,10 @@ public function getFormID() { /** * {@inheritdoc} */ - public function buildForm(array $form, array &$form_state, Node $node = NULL) { + public function buildForm(array $form, array &$form_state, EntityBCDecorator $node = NULL) { if (!isset($node->book)) { // The node is not part of any book yet - set default options. - $node->book = _book_link_defaults($node->nid); + $node->book = $this->bookManager->bookLinkDefaults($node->nid); } else { $node->book['original_bid'] = $node->book['bid']; @@ -49,11 +62,11 @@ public function buildForm(array $form, array &$form_state, Node $node = NULL) { // Find the depth limit for the parent select. if (!isset($node->book['parent_depth_limit'])) { - $node->book['parent_depth_limit'] = _book_parent_depth_limit($node->book); + $node->book['parent_depth_limit'] = $this->bookManager->bookParentDepthLimit($node->book); } $form['#node'] = $node; $form['#id'] = 'book-outline'; - _book_add_form_elements($form, $form_state, $node); + $this->bookManager->bookAddFormElements($form, $form_state, $node); $form['update'] = array( '#type' => 'submit', @@ -64,7 +77,7 @@ public function buildForm(array $form, array &$form_state, Node $node = NULL) { $form['remove'] = array( '#type' => 'submit', '#value' => t('Remove from book outline'), - '#access' => _book_node_is_removable($node), + '#access' => $this->bookManager->bookNodeIsRemovable($node), '#weight' => 20, '#submit' => array('book_remove_button_submit'), );