annotate core/modules/book/src/Plugin/Block/BookNavigationBlock.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 4c8ae668cc8c
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\book\Plugin\Block;
Chris@0 4
Chris@0 5 use Drupal\Core\Block\BlockBase;
Chris@0 6 use Drupal\book\BookManagerInterface;
Chris@0 7 use Drupal\Core\Cache\Cache;
Chris@0 8 use Drupal\Core\Form\FormStateInterface;
Chris@0 9 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
Chris@0 10 use Drupal\node\NodeInterface;
Chris@0 11 use Symfony\Component\DependencyInjection\ContainerInterface;
Chris@0 12 use Symfony\Component\HttpFoundation\RequestStack;
Chris@0 13 use Drupal\Core\Entity\EntityStorageInterface;
Chris@0 14
Chris@0 15 /**
Chris@0 16 * Provides a 'Book navigation' block.
Chris@0 17 *
Chris@0 18 * @Block(
Chris@0 19 * id = "book_navigation",
Chris@0 20 * admin_label = @Translation("Book navigation"),
Chris@0 21 * category = @Translation("Menus")
Chris@0 22 * )
Chris@0 23 */
Chris@0 24 class BookNavigationBlock extends BlockBase implements ContainerFactoryPluginInterface {
Chris@0 25
Chris@0 26 /**
Chris@0 27 * The request object.
Chris@0 28 *
Chris@0 29 * @var \Symfony\Component\HttpFoundation\RequestStack
Chris@0 30 */
Chris@0 31 protected $requestStack;
Chris@0 32
Chris@0 33 /**
Chris@0 34 * The book manager.
Chris@0 35 *
Chris@0 36 * @var \Drupal\book\BookManagerInterface
Chris@0 37 */
Chris@0 38 protected $bookManager;
Chris@0 39
Chris@0 40 /**
Chris@0 41 * The node storage.
Chris@0 42 *
Chris@0 43 * @var \Drupal\Core\Entity\EntityStorageInterface
Chris@0 44 */
Chris@0 45 protected $nodeStorage;
Chris@0 46
Chris@0 47 /**
Chris@0 48 * Constructs a new BookNavigationBlock instance.
Chris@0 49 *
Chris@0 50 * @param array $configuration
Chris@0 51 * A configuration array containing information about the plugin instance.
Chris@0 52 * @param string $plugin_id
Chris@0 53 * The plugin_id for the plugin instance.
Chris@0 54 * @param mixed $plugin_definition
Chris@0 55 * The plugin implementation definition.
Chris@0 56 * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
Chris@0 57 * The request stack object.
Chris@0 58 * @param \Drupal\book\BookManagerInterface $book_manager
Chris@0 59 * The book manager.
Chris@0 60 * @param \Drupal\Core\Entity\EntityStorageInterface $node_storage
Chris@0 61 * The node storage.
Chris@0 62 */
Chris@0 63 public function __construct(array $configuration, $plugin_id, $plugin_definition, RequestStack $request_stack, BookManagerInterface $book_manager, EntityStorageInterface $node_storage) {
Chris@0 64 parent::__construct($configuration, $plugin_id, $plugin_definition);
Chris@0 65
Chris@0 66 $this->requestStack = $request_stack;
Chris@0 67 $this->bookManager = $book_manager;
Chris@0 68 $this->nodeStorage = $node_storage;
Chris@0 69 }
Chris@0 70
Chris@0 71 /**
Chris@0 72 * {@inheritdoc}
Chris@0 73 */
Chris@0 74 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
Chris@0 75 return new static(
Chris@0 76 $configuration,
Chris@0 77 $plugin_id,
Chris@0 78 $plugin_definition,
Chris@0 79 $container->get('request_stack'),
Chris@0 80 $container->get('book.manager'),
Chris@0 81 $container->get('entity.manager')->getStorage('node')
Chris@0 82 );
Chris@0 83 }
Chris@0 84
Chris@0 85 /**
Chris@0 86 * {@inheritdoc}
Chris@0 87 */
Chris@0 88 public function defaultConfiguration() {
Chris@0 89 return [
Chris@0 90 'block_mode' => "all pages",
Chris@0 91 ];
Chris@0 92 }
Chris@0 93
Chris@0 94 /**
Chris@0 95 * {@inheritdoc}
Chris@0 96 */
Chris@0 97 public function blockForm($form, FormStateInterface $form_state) {
Chris@0 98 $options = [
Chris@0 99 'all pages' => $this->t('Show block on all pages'),
Chris@0 100 'book pages' => $this->t('Show block only on book pages'),
Chris@0 101 ];
Chris@0 102 $form['book_block_mode'] = [
Chris@0 103 '#type' => 'radios',
Chris@0 104 '#title' => $this->t('Book navigation block display'),
Chris@0 105 '#options' => $options,
Chris@0 106 '#default_value' => $this->configuration['block_mode'],
Chris@0 107 '#description' => $this->t("If <em>Show block on all pages</em> is selected, the block will contain the automatically generated menus for all of the site's books. If <em>Show block only on book pages</em> is selected, the block will contain only the one menu corresponding to the current page's book. In this case, if the current page is not in a book, no block will be displayed. The <em>Page specific visibility settings</em> or other visibility settings can be used in addition to selectively display this block."),
Chris@0 108 ];
Chris@0 109
Chris@0 110 return $form;
Chris@0 111 }
Chris@0 112
Chris@0 113 /**
Chris@0 114 * {@inheritdoc}
Chris@0 115 */
Chris@0 116 public function blockSubmit($form, FormStateInterface $form_state) {
Chris@0 117 $this->configuration['block_mode'] = $form_state->getValue('book_block_mode');
Chris@0 118 }
Chris@0 119
Chris@0 120 /**
Chris@0 121 * {@inheritdoc}
Chris@0 122 */
Chris@0 123 public function build() {
Chris@0 124 $current_bid = 0;
Chris@0 125
Chris@0 126 if ($node = $this->requestStack->getCurrentRequest()->get('node')) {
Chris@0 127 $current_bid = empty($node->book['bid']) ? 0 : $node->book['bid'];
Chris@0 128 }
Chris@0 129 if ($this->configuration['block_mode'] == 'all pages') {
Chris@0 130 $book_menus = [];
Chris@0 131 $pseudo_tree = [0 => ['below' => FALSE]];
Chris@0 132 foreach ($this->bookManager->getAllBooks() as $book_id => $book) {
Chris@0 133 if ($book['bid'] == $current_bid) {
Chris@0 134 // If the current page is a node associated with a book, the menu
Chris@0 135 // needs to be retrieved.
Chris@0 136 $data = $this->bookManager->bookTreeAllData($node->book['bid'], $node->book);
Chris@0 137 $book_menus[$book_id] = $this->bookManager->bookTreeOutput($data);
Chris@0 138 }
Chris@0 139 else {
Chris@0 140 // Since we know we will only display a link to the top node, there
Chris@0 141 // is no reason to run an additional menu tree query for each book.
Chris@0 142 $book['in_active_trail'] = FALSE;
Chris@0 143 // Check whether user can access the book link.
Chris@0 144 $book_node = $this->nodeStorage->load($book['nid']);
Chris@0 145 $book['access'] = $book_node->access('view');
Chris@0 146 $pseudo_tree[0]['link'] = $book;
Chris@0 147 $book_menus[$book_id] = $this->bookManager->bookTreeOutput($pseudo_tree);
Chris@0 148 }
Chris@0 149 $book_menus[$book_id] += [
Chris@0 150 '#book_title' => $book['title'],
Chris@0 151 ];
Chris@0 152 }
Chris@0 153 if ($book_menus) {
Chris@0 154 return [
Chris@0 155 '#theme' => 'book_all_books_block',
Chris@0 156 ] + $book_menus;
Chris@0 157 }
Chris@0 158 }
Chris@0 159 elseif ($current_bid) {
Chris@0 160 // Only display this block when the user is browsing a book and do
Chris@0 161 // not show unpublished books.
Chris@0 162 $nid = \Drupal::entityQuery('node')
Chris@0 163 ->condition('nid', $node->book['bid'], '=')
Chris@0 164 ->condition('status', NodeInterface::PUBLISHED)
Chris@0 165 ->execute();
Chris@0 166
Chris@0 167 // Only show the block if the user has view access for the top-level node.
Chris@0 168 if ($nid) {
Chris@0 169 $tree = $this->bookManager->bookTreeAllData($node->book['bid'], $node->book);
Chris@0 170 // There should only be one element at the top level.
Chris@0 171 $data = array_shift($tree);
Chris@0 172 $below = $this->bookManager->bookTreeOutput($data['below']);
Chris@0 173 if (!empty($below)) {
Chris@0 174 return $below;
Chris@0 175 }
Chris@0 176 }
Chris@0 177 }
Chris@0 178 return [];
Chris@0 179 }
Chris@0 180
Chris@0 181 /**
Chris@0 182 * {@inheritdoc}
Chris@0 183 */
Chris@0 184 public function getCacheContexts() {
Chris@0 185 return Cache::mergeContexts(parent::getCacheContexts(), ['route.book_navigation']);
Chris@0 186 }
Chris@0 187
Chris@0 188 /**
Chris@0 189 * {@inheritdoc}
Chris@0 190 *
Chris@0 191 * @todo Make cacheable in https://www.drupal.org/node/2483181
Chris@0 192 */
Chris@0 193 public function getCacheMaxAge() {
Chris@0 194 return 0;
Chris@0 195 }
Chris@0 196
Chris@0 197 }