annotate core/modules/block/src/Controller/BlockLibraryController.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\block\Controller;
Chris@0 4
Chris@0 5 use Drupal\Component\Serialization\Json;
Chris@0 6 use Drupal\Core\Block\BlockManagerInterface;
Chris@0 7 use Drupal\Core\Controller\ControllerBase;
Chris@0 8 use Drupal\Core\EventSubscriber\MainContentViewSubscriber;
Chris@0 9 use Drupal\Core\Menu\LocalActionManagerInterface;
Chris@0 10 use Drupal\Core\Plugin\Context\LazyContextRepository;
Chris@0 11 use Drupal\Core\Routing\RouteMatchInterface;
Chris@0 12 use Drupal\Core\Url;
Chris@0 13 use Symfony\Component\DependencyInjection\ContainerInterface;
Chris@0 14 use Symfony\Component\HttpFoundation\Request;
Chris@0 15
Chris@0 16 /**
Chris@0 17 * Provides a list of block plugins to be added to the layout.
Chris@0 18 */
Chris@0 19 class BlockLibraryController extends ControllerBase {
Chris@0 20
Chris@0 21 /**
Chris@0 22 * The block manager.
Chris@0 23 *
Chris@0 24 * @var \Drupal\Core\Block\BlockManagerInterface
Chris@0 25 */
Chris@0 26 protected $blockManager;
Chris@0 27
Chris@0 28 /**
Chris@0 29 * The context repository.
Chris@0 30 *
Chris@0 31 * @var \Drupal\Core\Plugin\Context\LazyContextRepository
Chris@0 32 */
Chris@0 33 protected $contextRepository;
Chris@0 34
Chris@0 35 /**
Chris@0 36 * The route match.
Chris@0 37 *
Chris@0 38 * @var \Drupal\Core\Routing\RouteMatchInterface
Chris@0 39 */
Chris@0 40 protected $routeMatch;
Chris@0 41
Chris@0 42 /**
Chris@0 43 * The local action manager.
Chris@0 44 *
Chris@0 45 * @var \Drupal\Core\Menu\LocalActionManagerInterface
Chris@0 46 */
Chris@0 47 protected $localActionManager;
Chris@0 48
Chris@0 49 /**
Chris@0 50 * Constructs a BlockLibraryController object.
Chris@0 51 *
Chris@0 52 * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
Chris@0 53 * The block manager.
Chris@0 54 * @param \Drupal\Core\Plugin\Context\LazyContextRepository $context_repository
Chris@0 55 * The context repository.
Chris@0 56 * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
Chris@0 57 * The current route match.
Chris@0 58 * @param \Drupal\Core\Menu\LocalActionManagerInterface $local_action_manager
Chris@0 59 * The local action manager.
Chris@0 60 */
Chris@0 61 public function __construct(BlockManagerInterface $block_manager, LazyContextRepository $context_repository, RouteMatchInterface $route_match, LocalActionManagerInterface $local_action_manager) {
Chris@0 62 $this->blockManager = $block_manager;
Chris@0 63 $this->routeMatch = $route_match;
Chris@0 64 $this->localActionManager = $local_action_manager;
Chris@0 65 $this->contextRepository = $context_repository;
Chris@0 66 }
Chris@0 67
Chris@0 68 /**
Chris@0 69 * {@inheritdoc}
Chris@0 70 */
Chris@0 71 public static function create(ContainerInterface $container) {
Chris@0 72 return new static(
Chris@0 73 $container->get('plugin.manager.block'),
Chris@0 74 $container->get('context.repository'),
Chris@0 75 $container->get('current_route_match'),
Chris@0 76 $container->get('plugin.manager.menu.local_action')
Chris@0 77 );
Chris@0 78 }
Chris@0 79
Chris@0 80 /**
Chris@0 81 * Shows a list of blocks that can be added to a theme's layout.
Chris@0 82 *
Chris@0 83 * @param \Symfony\Component\HttpFoundation\Request $request
Chris@0 84 * The current request.
Chris@0 85 * @param string $theme
Chris@0 86 * Theme key of the block list.
Chris@0 87 *
Chris@0 88 * @return array
Chris@0 89 * A render array as expected by the renderer.
Chris@0 90 */
Chris@0 91 public function listBlocks(Request $request, $theme) {
Chris@0 92 // Since modals do not render any other part of the page, we need to render
Chris@0 93 // them manually as part of this listing.
Chris@0 94 if ($request->query->get(MainContentViewSubscriber::WRAPPER_FORMAT) === 'drupal_modal') {
Chris@0 95 $build['local_actions'] = $this->buildLocalActions();
Chris@0 96 }
Chris@0 97
Chris@0 98 $headers = [
Chris@0 99 ['data' => $this->t('Block')],
Chris@0 100 ['data' => $this->t('Category')],
Chris@0 101 ['data' => $this->t('Operations')],
Chris@0 102 ];
Chris@0 103
Chris@17 104 $region = $request->query->get('region');
Chris@17 105 $weight = $request->query->get('weight');
Chris@17 106
Chris@0 107 // Only add blocks which work without any available context.
Chris@17 108 $definitions = $this->blockManager->getFilteredDefinitions('block_ui', $this->contextRepository->getAvailableContexts(), [
Chris@17 109 'theme' => $theme,
Chris@17 110 'region' => $region,
Chris@17 111 ]);
Chris@0 112 // Order by category, and then by admin label.
Chris@0 113 $definitions = $this->blockManager->getSortedDefinitions($definitions);
Chris@14 114 // Filter out definitions that are not intended to be placed by the UI.
Chris@14 115 $definitions = array_filter($definitions, function (array $definition) {
Chris@14 116 return empty($definition['_block_ui_hidden']);
Chris@14 117 });
Chris@0 118
Chris@0 119 $rows = [];
Chris@0 120 foreach ($definitions as $plugin_id => $plugin_definition) {
Chris@0 121 $row = [];
Chris@0 122 $row['title']['data'] = [
Chris@0 123 '#type' => 'inline_template',
Chris@0 124 '#template' => '<div class="block-filter-text-source">{{ label }}</div>',
Chris@0 125 '#context' => [
Chris@0 126 'label' => $plugin_definition['admin_label'],
Chris@0 127 ],
Chris@0 128 ];
Chris@0 129 $row['category']['data'] = $plugin_definition['category'];
Chris@0 130 $links['add'] = [
Chris@0 131 'title' => $this->t('Place block'),
Chris@0 132 'url' => Url::fromRoute('block.admin_add', ['plugin_id' => $plugin_id, 'theme' => $theme]),
Chris@0 133 'attributes' => [
Chris@0 134 'class' => ['use-ajax'],
Chris@0 135 'data-dialog-type' => 'modal',
Chris@0 136 'data-dialog-options' => Json::encode([
Chris@0 137 'width' => 700,
Chris@0 138 ]),
Chris@0 139 ],
Chris@0 140 ];
Chris@0 141 if ($region) {
Chris@0 142 $links['add']['query']['region'] = $region;
Chris@0 143 }
Chris@0 144 if (isset($weight)) {
Chris@0 145 $links['add']['query']['weight'] = $weight;
Chris@0 146 }
Chris@0 147 $row['operations']['data'] = [
Chris@0 148 '#type' => 'operations',
Chris@0 149 '#links' => $links,
Chris@0 150 ];
Chris@0 151 $rows[] = $row;
Chris@0 152 }
Chris@0 153
Chris@0 154 $build['#attached']['library'][] = 'block/drupal.block.admin';
Chris@0 155
Chris@0 156 $build['filter'] = [
Chris@0 157 '#type' => 'search',
Chris@0 158 '#title' => $this->t('Filter'),
Chris@0 159 '#title_display' => 'invisible',
Chris@0 160 '#size' => 30,
Chris@0 161 '#placeholder' => $this->t('Filter by block name'),
Chris@0 162 '#attributes' => [
Chris@0 163 'class' => ['block-filter-text'],
Chris@0 164 'data-element' => '.block-add-table',
Chris@0 165 'title' => $this->t('Enter a part of the block name to filter by.'),
Chris@0 166 ],
Chris@0 167 ];
Chris@0 168
Chris@0 169 $build['blocks'] = [
Chris@0 170 '#type' => 'table',
Chris@0 171 '#header' => $headers,
Chris@0 172 '#rows' => $rows,
Chris@0 173 '#empty' => $this->t('No blocks available.'),
Chris@0 174 '#attributes' => [
Chris@0 175 'class' => ['block-add-table'],
Chris@0 176 ],
Chris@0 177 ];
Chris@0 178
Chris@0 179 return $build;
Chris@0 180 }
Chris@0 181
Chris@0 182 /**
Chris@0 183 * Builds the local actions for this listing.
Chris@0 184 *
Chris@0 185 * @return array
Chris@0 186 * An array of local actions for this listing.
Chris@0 187 */
Chris@0 188 protected function buildLocalActions() {
Chris@0 189 $build = $this->localActionManager->getActionsForRoute($this->routeMatch->getRouteName());
Chris@0 190 // Without this workaround, the action links will be rendered as <li> with
Chris@0 191 // no wrapping <ul> element.
Chris@0 192 if (!empty($build)) {
Chris@0 193 $build['#prefix'] = '<ul class="action-links">';
Chris@0 194 $build['#suffix'] = '</ul>';
Chris@0 195 }
Chris@0 196 return $build;
Chris@0 197 }
Chris@0 198
Chris@0 199 }