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