Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
0.00% |
0 / 175 |
|
0.00% |
0 / 74 |
|
0.00% |
0 / 62 |
|
0.00% |
0 / 9 |
CRAP | |
0.00% |
0 / 1 |
| BlockLibraryPanel | |
0.00% |
0 / 168 |
|
0.00% |
0 / 74 |
|
0.00% |
0 / 62 |
|
0.00% |
0 / 9 |
1482 | |
0.00% |
0 / 1 |
| create | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| defaultConfiguration | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| buildConfigurationForm | |
0.00% |
0 / 38 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| configurationSummary | |
0.00% |
0 / 18 |
|
0.00% |
0 / 11 |
|
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
56 | |||
| build | |
0.00% |
0 / 34 |
|
0.00% |
0 / 13 |
|
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
42 | |||
| buildCategorySection | |
0.00% |
0 / 16 |
|
0.00% |
0 / 11 |
|
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
30 | |||
| getSources | |
0.00% |
0 / 23 |
|
0.00% |
0 / 15 |
|
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
56 | |||
| getProvidersOptions | |
0.00% |
0 / 8 |
|
0.00% |
0 / 4 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| getProviders | |
0.00% |
0 / 18 |
|
0.00% |
0 / 17 |
|
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
72 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Drupal\display_builder\Plugin\display_builder\Island; |
| 6 | |
| 7 | use Drupal\Core\Extension\ModuleExtensionList; |
| 8 | use Drupal\Core\Form\FormStateInterface; |
| 9 | use Drupal\Core\StringTranslation\TranslatableMarkup; |
| 10 | use Drupal\display_builder\Attribute\Island; |
| 11 | use Drupal\display_builder\BlockLibrarySourceHelper; |
| 12 | use Drupal\display_builder\InstanceInterface; |
| 13 | use Drupal\display_builder\Island\IslandConfigurationFormInterface; |
| 14 | use Drupal\display_builder\Island\IslandConfigurationFormTrait; |
| 15 | use Drupal\display_builder\Island\IslandPluginBase; |
| 16 | use Drupal\display_builder\Island\IslandType; |
| 17 | use Drupal\display_builder\SourceWithSlotsInterface; |
| 18 | use Drupal\ui_patterns\SourcePluginBase; |
| 19 | use Drupal\ui_patterns\SourceWithChoicesInterface; |
| 20 | use Symfony\Component\DependencyInjection\ContainerInterface; |
| 21 | |
| 22 | /** |
| 23 | * Block library island plugin implementation. |
| 24 | */ |
| 25 | #[Island( |
| 26 | id: 'block_library', |
| 27 | enabled_by_default: TRUE, |
| 28 | label: new TranslatableMarkup('Blocks'), |
| 29 | description: new TranslatableMarkup('List of available blocks.'), |
| 30 | type: IslandType::Library, |
| 31 | icon: 'bricks', |
| 32 | )] |
| 33 | class BlockLibraryPanel extends IslandPluginBase implements IslandConfigurationFormInterface { |
| 34 | |
| 35 | use IslandConfigurationFormTrait; |
| 36 | |
| 37 | private const HIDE_SOURCE = [ |
| 38 | 'component', |
| 39 | // Token is deprecated in UI Patterns; 'Textfield' allow token. |
| 40 | 'token', |
| 41 | 'wysiwyg', |
| 42 | ]; |
| 43 | |
| 44 | private const HIDE_PROVIDER = ['ui_patterns_blocks']; |
| 45 | |
| 46 | /** |
| 47 | * The sources. |
| 48 | */ |
| 49 | protected array $sources = []; |
| 50 | |
| 51 | /** |
| 52 | * The module extension list service. |
| 53 | */ |
| 54 | protected ModuleExtensionList $moduleList; |
| 55 | |
| 56 | /** |
| 57 | * {@inheritdoc} |
| 58 | */ |
| 59 | public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static { |
| 60 | $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition); |
| 61 | $instance->moduleList = $container->get('extension.list.module'); |
| 62 | |
| 63 | return $instance; |
| 64 | } |
| 65 | |
| 66 | /** |
| 67 | * {@inheritdoc} |
| 68 | */ |
| 69 | public function defaultConfiguration(): array { |
| 70 | return [ |
| 71 | 'exclude' => [ |
| 72 | 'devel', |
| 73 | 'htmx', |
| 74 | 'shortcut', |
| 75 | ], |
| 76 | 'exclude_id' => '', |
| 77 | 'show' => 'grouped', |
| 78 | 'preview' => TRUE, |
| 79 | ]; |
| 80 | } |
| 81 | |
| 82 | /** |
| 83 | * {@inheritdoc} |
| 84 | */ |
| 85 | public function buildConfigurationForm(array $form, FormStateInterface $form_state): array { |
| 86 | $configuration = $this->getConfiguration(); |
| 87 | |
| 88 | $form['display'] = [ |
| 89 | '#type' => 'fieldset', |
| 90 | '#title' => $this->t('Display'), |
| 91 | ]; |
| 92 | |
| 93 | $form['display']['show'] = [ |
| 94 | '#type' => 'select', |
| 95 | '#title' => $this->t('Display blocks as'), |
| 96 | '#default_value' => $configuration['show'], |
| 97 | '#options' => [ |
| 98 | 'grouped' => $this->t('grouped'), |
| 99 | 'flat' => $this->t('flat list'), |
| 100 | ], |
| 101 | ]; |
| 102 | |
| 103 | $form['display']['preview'] = [ |
| 104 | '#type' => 'checkbox', |
| 105 | '#title' => $this->t('Enable preview on hover'), |
| 106 | '#description' => $this->t('Enable or disable the preview of components when hovering over them.'), |
| 107 | '#default_value' => $configuration['preview'], |
| 108 | ]; |
| 109 | |
| 110 | $form['configuration'] = [ |
| 111 | '#type' => 'fieldset', |
| 112 | '#title' => $this->t('Configuration'), |
| 113 | ]; |
| 114 | |
| 115 | $form['configuration']['exclude'] = [ |
| 116 | '#type' => 'checkboxes', |
| 117 | '#title' => $this->t('Exclude from modules'), |
| 118 | '#description' => $this->t('Select the modules which blocks have to be excluded from the block library.'), |
| 119 | '#options' => $this->getProvidersOptions(), |
| 120 | '#default_value' => $configuration['exclude'], |
| 121 | ]; |
| 122 | |
| 123 | $form['configuration']['exclude_id'] = [ |
| 124 | '#type' => 'textarea', |
| 125 | '#title' => $this->t('Exclude by id'), |
| 126 | '#description' => $this->t('Provide a list of id to exclude. One id by line, source id is used. Example: "help_block views_block:comments_recent-block_1 system_menu_block:account field:node:article:vid".'), |
| 127 | '#default_value' => $configuration['exclude_id'], |
| 128 | ]; |
| 129 | |
| 130 | return $form; |
| 131 | } |
| 132 | |
| 133 | /** |
| 134 | * {@inheritdoc} |
| 135 | */ |
| 136 | public function configurationSummary(): array { |
| 137 | $configuration = $this->getConfiguration(); |
| 138 | |
| 139 | $summary[] = $this->t('Blocks displayed as: <em>@list</em>', [ |
| 140 | '@list' => match ($configuration['show']) { |
| 141 | 'flat' => $this->t('flat'), |
| 142 | default => $this->t('grouped'), |
| 143 | }, |
| 144 | ]); |
| 145 | |
| 146 | if ($configuration['preview']) { |
| 147 | $summary[] = $this->t('Preview on hover enabled'); |
| 148 | } |
| 149 | |
| 150 | $summary[] = $this->t('Excluded modules: @exclude', [ |
| 151 | '@exclude' => \implode(', ', \array_filter($configuration['exclude'] ?? []) ?: [$this->t('None')]), |
| 152 | ]); |
| 153 | |
| 154 | if (\strlen($configuration['exclude_id'] ?? '') > 5) { |
| 155 | $value = \preg_split('/\r\n|\r|\n/', \trim($configuration['exclude_id'] ?? '')); |
| 156 | |
| 157 | if ($value === FALSE) { |
| 158 | $summary[] = $this->t('Block(s) excluded'); |
| 159 | } |
| 160 | else { |
| 161 | $summary[] = $this->formatPlural(\count($value), '@count block excluded', '@count blocks excluded by id'); |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | return $summary; |
| 166 | } |
| 167 | |
| 168 | /** |
| 169 | * {@inheritdoc} |
| 170 | */ |
| 171 | public function build(InstanceInterface $builder, array $data = [], array $options = []): array { |
| 172 | $builder_id = (string) $builder->id(); |
| 173 | $configuration = $this->getConfiguration(); |
| 174 | |
| 175 | $exclude_providers = \array_merge( |
| 176 | $configuration['exclude'] ?? [], |
| 177 | self::HIDE_PROVIDER |
| 178 | ); |
| 179 | $exclude_by_id = \preg_split('/\r\n|\r|\n/', \trim($configuration['exclude_id'] ?? '')) ?: []; |
| 180 | |
| 181 | $build = []; |
| 182 | |
| 183 | if ($configuration['show'] === 'grouped') { |
| 184 | $categories = BlockLibrarySourceHelper::getGroupedChoices( |
| 185 | $this->getSources(), |
| 186 | $exclude_providers, |
| 187 | $exclude_by_id, |
| 188 | (bool) $configuration['preview'], |
| 189 | ); |
| 190 | |
| 191 | foreach ($categories as $category_data) { |
| 192 | $build[] = $this->buildCategorySection($category_data, $builder_id, (bool) $configuration['preview']); |
| 193 | } |
| 194 | } |
| 195 | else { |
| 196 | $choices = BlockLibrarySourceHelper::getChoices( |
| 197 | $this->getSources(), |
| 198 | $exclude_providers, |
| 199 | $exclude_by_id, |
| 200 | (bool) $configuration['preview'], |
| 201 | ); |
| 202 | |
| 203 | foreach ($choices as $choice) { |
| 204 | if ($configuration['preview']) { |
| 205 | $build[] = $this->buildPlaceholderListWithPreview($builder_id, $choice['label'], $data, $choice['preview'], $choice['keywords']); |
| 206 | } |
| 207 | else { |
| 208 | $build[] = $this->buildPlaceholderList($choice['label'], $data, $choice['keywords']); |
| 209 | } |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | return [ |
| 214 | '#type' => 'component', |
| 215 | '#component' => 'display_builder:library_panel', |
| 216 | '#slots' => [ |
| 217 | 'content' => $this->buildDraggables($builder_id, $build), |
| 218 | ], |
| 219 | ]; |
| 220 | } |
| 221 | |
| 222 | /** |
| 223 | * Build a category section. |
| 224 | * |
| 225 | * @param array $category_data |
| 226 | * The category data. |
| 227 | * @param string $builder_id |
| 228 | * The builder ID. |
| 229 | * @param bool $preview |
| 230 | * Whether to show preview on hover. |
| 231 | * |
| 232 | * @return array |
| 233 | * The render array for the category section. |
| 234 | */ |
| 235 | private function buildCategorySection(array $category_data, string $builder_id, bool $preview): array { |
| 236 | $section = []; |
| 237 | |
| 238 | if (!empty($category_data['label'])) { |
| 239 | $section[] = [ |
| 240 | '#type' => 'html_tag', |
| 241 | '#tag' => 'h4', |
| 242 | '#attributes' => [ |
| 243 | 'class' => ['db-placeholder__group', 'db-filter-hide-on-search'], |
| 244 | ], |
| 245 | '#value' => $category_data['label'], |
| 246 | ]; |
| 247 | } |
| 248 | |
| 249 | foreach ($category_data['choices'] as $choice) { |
| 250 | $label = $choice['label'] ?? '-'; |
| 251 | |
| 252 | if ($preview && $choice['preview']) { |
| 253 | $section[] = $this->buildPlaceholderListWithPreview($builder_id, $label, $choice['data'] ?? [], $choice['preview'], $choice['keywords'] ?? ''); |
| 254 | } |
| 255 | else { |
| 256 | $section[] = $this->buildPlaceholderList($label, $choice['data'] ?? [], $choice['keywords'] ?? ''); |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | return $section; |
| 261 | } |
| 262 | |
| 263 | /** |
| 264 | * Returns all possible sources. |
| 265 | * |
| 266 | * @throws \Drupal\Component\Plugin\Exception\PluginException |
| 267 | * |
| 268 | * @return array<string, array> |
| 269 | * An array of sources. |
| 270 | */ |
| 271 | private function getSources(): array { |
| 272 | if (!empty($this->sources)) { |
| 273 | return $this->sources; |
| 274 | } |
| 275 | |
| 276 | $definitions = $this->sourceManager->getDefinitionsForPropType('slot', $this->configuration['contexts'] ?? []); |
| 277 | $slot_definition = ['ui_patterns' => ['type_definition' => $this->sourceManager->getSlotPropType()]]; |
| 278 | |
| 279 | foreach ($definitions as $source_id => $definition) { |
| 280 | // A block is a source for slots but without slots. |
| 281 | if (\is_a($definition['class'], SourceWithSlotsInterface::class, TRUE)) { |
| 282 | continue; |
| 283 | } |
| 284 | |
| 285 | if (\in_array($source_id, self::HIDE_SOURCE, TRUE)) { |
| 286 | continue; |
| 287 | } |
| 288 | |
| 289 | try { |
| 290 | $source = $this->sourceManager->createInstance( |
| 291 | $source_id, |
| 292 | SourcePluginBase::buildConfiguration('slot', $slot_definition, ['source' => []], $this->configuration['contexts'] ?? []) |
| 293 | ); |
| 294 | } |
| 295 | catch (\Throwable $e) { |
| 296 | $this->logger->error('Invalid source found: %message', ['%message' => $e->getMessage()]); |
| 297 | |
| 298 | continue; |
| 299 | } |
| 300 | |
| 301 | $this->sources[$source_id] = [ |
| 302 | 'definition' => $definition, |
| 303 | 'source' => $source, |
| 304 | ]; |
| 305 | |
| 306 | if ($source instanceof SourceWithChoicesInterface) { |
| 307 | $this->sources[$source_id]['choices'] = $source->getChoices(); |
| 308 | } |
| 309 | } |
| 310 | |
| 311 | return $this->sources; |
| 312 | } |
| 313 | |
| 314 | /** |
| 315 | * Get providers options for select input. |
| 316 | * |
| 317 | * @return array |
| 318 | * An associative array with module ID as key and module description as |
| 319 | * value. |
| 320 | */ |
| 321 | private function getProvidersOptions(): array { |
| 322 | $options = []; |
| 323 | |
| 324 | foreach ($this->getProviders() as $provider_id => $provider) { |
| 325 | $params = [ |
| 326 | '@name' => $provider['name'], |
| 327 | '@count' => $provider['count'], |
| 328 | ]; |
| 329 | $options[$provider_id] = $this->formatPlural($provider['count'], '@name (@count block)', '@name (@count blocks)', $params); |
| 330 | } |
| 331 | |
| 332 | return $options; |
| 333 | } |
| 334 | |
| 335 | /** |
| 336 | * Get all providers. |
| 337 | * |
| 338 | * @return array |
| 339 | * Drupal modules definitions, keyed by extension ID |
| 340 | */ |
| 341 | private function getProviders(): array { |
| 342 | $sources = $this->getSources(); |
| 343 | $providers = []; |
| 344 | $modules = $this->moduleList->getAllInstalledInfo(); |
| 345 | |
| 346 | foreach ($sources as $source_data) { |
| 347 | if (!isset($source_data['choices'])) { |
| 348 | continue; |
| 349 | } |
| 350 | $choices = $source_data['choices']; |
| 351 | |
| 352 | foreach ($choices as $choice) { |
| 353 | $provider = $choice['provider'] ?? ''; |
| 354 | |
| 355 | if (!$provider || \in_array($provider, self::HIDE_PROVIDER, TRUE)) { |
| 356 | continue; |
| 357 | } |
| 358 | |
| 359 | if (!isset($modules[$provider])) { |
| 360 | // If the provider is not a module, skip it. |
| 361 | continue; |
| 362 | } |
| 363 | |
| 364 | if (!isset($providers[$provider])) { |
| 365 | $providers[$provider] = $modules[$provider]; |
| 366 | $providers[$provider]['count'] = 0; |
| 367 | } |
| 368 | ++$providers[$provider]['count']; |
| 369 | } |
| 370 | } |
| 371 | |
| 372 | return $providers; |
| 373 | } |
| 374 | |
| 375 | } |
Below are the source code lines that represent each code branch as identified by Xdebug. Please note a branch is not
necessarily coterminous with a line, a line may contain multiple branches and therefore show up more than once.
Please also be aware that some branches may be implicit rather than explicit, e.g. an if statement
always has an else as part of its logical flow even if you didn't write one.
| 171 | public function build(InstanceInterface $builder, array $data = [], array $options = []): array { |
| 172 | $builder_id = (string) $builder->id(); |
| 173 | $configuration = $this->getConfiguration(); |
| 174 | |
| 175 | $exclude_providers = \array_merge( |
| 176 | $configuration['exclude'] ?? [], |
| 177 | self::HIDE_PROVIDER |
| 178 | ); |
| 179 | $exclude_by_id = \preg_split('/\r\n|\r|\n/', \trim($configuration['exclude_id'] ?? '')) ?: []; |
| 180 | |
| 181 | $build = []; |
| 182 | |
| 183 | if ($configuration['show'] === 'grouped') { |
| 184 | $categories = BlockLibrarySourceHelper::getGroupedChoices( |
| 185 | $this->getSources(), |
| 186 | $exclude_providers, |
| 187 | $exclude_by_id, |
| 188 | (bool) $configuration['preview'], |
| 189 | ); |
| 190 | |
| 191 | foreach ($categories as $category_data) { |
| 191 | foreach ($categories as $category_data) { |
| 191 | foreach ($categories as $category_data) { |
| 192 | $build[] = $this->buildCategorySection($category_data, $builder_id, (bool) $configuration['preview']); |
| 183 | if ($configuration['show'] === 'grouped') { |
| 184 | $categories = BlockLibrarySourceHelper::getGroupedChoices( |
| 185 | $this->getSources(), |
| 186 | $exclude_providers, |
| 187 | $exclude_by_id, |
| 188 | (bool) $configuration['preview'], |
| 189 | ); |
| 190 | |
| 191 | foreach ($categories as $category_data) { |
| 196 | $choices = BlockLibrarySourceHelper::getChoices( |
| 197 | $this->getSources(), |
| 198 | $exclude_providers, |
| 199 | $exclude_by_id, |
| 200 | (bool) $configuration['preview'], |
| 201 | ); |
| 202 | |
| 203 | foreach ($choices as $choice) { |
| 203 | foreach ($choices as $choice) { |
| 204 | if ($configuration['preview']) { |
| 204 | if ($configuration['preview']) { |
| 205 | $build[] = $this->buildPlaceholderListWithPreview($builder_id, $choice['label'], $data, $choice['preview'], $choice['keywords']); |
| 203 | foreach ($choices as $choice) { |
| 204 | if ($configuration['preview']) { |
| 205 | $build[] = $this->buildPlaceholderListWithPreview($builder_id, $choice['label'], $data, $choice['preview'], $choice['keywords']); |
| 206 | } |
| 207 | else { |
| 208 | $build[] = $this->buildPlaceholderList($choice['label'], $data, $choice['keywords']); |
| 203 | foreach ($choices as $choice) { |
| 203 | foreach ($choices as $choice) { |
| 204 | if ($configuration['preview']) { |
| 205 | $build[] = $this->buildPlaceholderListWithPreview($builder_id, $choice['label'], $data, $choice['preview'], $choice['keywords']); |
| 206 | } |
| 207 | else { |
| 208 | $build[] = $this->buildPlaceholderList($choice['label'], $data, $choice['keywords']); |
| 209 | } |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | return [ |
| 214 | '#type' => 'component', |
| 214 | '#type' => 'component', |
| 215 | '#component' => 'display_builder:library_panel', |
| 216 | '#slots' => [ |
| 217 | 'content' => $this->buildDraggables($builder_id, $build), |
| 218 | ], |
| 219 | ]; |
| 220 | } |
| 235 | private function buildCategorySection(array $category_data, string $builder_id, bool $preview): array { |
| 236 | $section = []; |
| 237 | |
| 238 | if (!empty($category_data['label'])) { |
| 240 | '#type' => 'html_tag', |
| 241 | '#tag' => 'h4', |
| 242 | '#attributes' => [ |
| 243 | 'class' => ['db-placeholder__group', 'db-filter-hide-on-search'], |
| 244 | ], |
| 245 | '#value' => $category_data['label'], |
| 246 | ]; |
| 247 | } |
| 248 | |
| 249 | foreach ($category_data['choices'] as $choice) { |
| 249 | foreach ($category_data['choices'] as $choice) { |
| 249 | foreach ($category_data['choices'] as $choice) { |
| 250 | $label = $choice['label'] ?? '-'; |
| 251 | |
| 252 | if ($preview && $choice['preview']) { |
| 252 | if ($preview && $choice['preview']) { |
| 252 | if ($preview && $choice['preview']) { |
| 252 | if ($preview && $choice['preview']) { |
| 253 | $section[] = $this->buildPlaceholderListWithPreview($builder_id, $label, $choice['data'] ?? [], $choice['preview'], $choice['keywords'] ?? ''); |
| 249 | foreach ($category_data['choices'] as $choice) { |
| 250 | $label = $choice['label'] ?? '-'; |
| 251 | |
| 252 | if ($preview && $choice['preview']) { |
| 253 | $section[] = $this->buildPlaceholderListWithPreview($builder_id, $label, $choice['data'] ?? [], $choice['preview'], $choice['keywords'] ?? ''); |
| 254 | } |
| 255 | else { |
| 256 | $section[] = $this->buildPlaceholderList($label, $choice['data'] ?? [], $choice['keywords'] ?? ''); |
| 249 | foreach ($category_data['choices'] as $choice) { |
| 249 | foreach ($category_data['choices'] as $choice) { |
| 250 | $label = $choice['label'] ?? '-'; |
| 251 | |
| 252 | if ($preview && $choice['preview']) { |
| 253 | $section[] = $this->buildPlaceholderListWithPreview($builder_id, $label, $choice['data'] ?? [], $choice['preview'], $choice['keywords'] ?? ''); |
| 254 | } |
| 255 | else { |
| 256 | $section[] = $this->buildPlaceholderList($label, $choice['data'] ?? [], $choice['keywords'] ?? ''); |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | return $section; |
| 261 | } |
| 85 | public function buildConfigurationForm(array $form, FormStateInterface $form_state): array { |
| 86 | $configuration = $this->getConfiguration(); |
| 87 | |
| 88 | $form['display'] = [ |
| 89 | '#type' => 'fieldset', |
| 90 | '#title' => $this->t('Display'), |
| 91 | ]; |
| 92 | |
| 93 | $form['display']['show'] = [ |
| 94 | '#type' => 'select', |
| 95 | '#title' => $this->t('Display blocks as'), |
| 96 | '#default_value' => $configuration['show'], |
| 97 | '#options' => [ |
| 98 | 'grouped' => $this->t('grouped'), |
| 99 | 'flat' => $this->t('flat list'), |
| 100 | ], |
| 101 | ]; |
| 102 | |
| 103 | $form['display']['preview'] = [ |
| 104 | '#type' => 'checkbox', |
| 105 | '#title' => $this->t('Enable preview on hover'), |
| 106 | '#description' => $this->t('Enable or disable the preview of components when hovering over them.'), |
| 107 | '#default_value' => $configuration['preview'], |
| 108 | ]; |
| 109 | |
| 110 | $form['configuration'] = [ |
| 111 | '#type' => 'fieldset', |
| 112 | '#title' => $this->t('Configuration'), |
| 113 | ]; |
| 114 | |
| 115 | $form['configuration']['exclude'] = [ |
| 116 | '#type' => 'checkboxes', |
| 117 | '#title' => $this->t('Exclude from modules'), |
| 118 | '#description' => $this->t('Select the modules which blocks have to be excluded from the block library.'), |
| 119 | '#options' => $this->getProvidersOptions(), |
| 120 | '#default_value' => $configuration['exclude'], |
| 121 | ]; |
| 122 | |
| 123 | $form['configuration']['exclude_id'] = [ |
| 124 | '#type' => 'textarea', |
| 125 | '#title' => $this->t('Exclude by id'), |
| 126 | '#description' => $this->t('Provide a list of id to exclude. One id by line, source id is used. Example: "help_block views_block:comments_recent-block_1 system_menu_block:account field:node:article:vid".'), |
| 127 | '#default_value' => $configuration['exclude_id'], |
| 128 | ]; |
| 129 | |
| 130 | return $form; |
| 131 | } |
| 137 | $configuration = $this->getConfiguration(); |
| 138 | |
| 139 | $summary[] = $this->t('Blocks displayed as: <em>@list</em>', [ |
| 140 | '@list' => match ($configuration['show']) { |
| 141 | 'flat' => $this->t('flat'), |
| 141 | 'flat' => $this->t('flat'), |
| 141 | 'flat' => $this->t('flat'), |
| 142 | default => $this->t('grouped'), |
| 142 | default => $this->t('grouped'), |
| 143 | }, |
| 144 | ]); |
| 145 | |
| 146 | if ($configuration['preview']) { |
| 147 | $summary[] = $this->t('Preview on hover enabled'); |
| 148 | } |
| 149 | |
| 150 | $summary[] = $this->t('Excluded modules: @exclude', [ |
| 150 | $summary[] = $this->t('Excluded modules: @exclude', [ |
| 151 | '@exclude' => \implode(', ', \array_filter($configuration['exclude'] ?? []) ?: [$this->t('None')]), |
| 152 | ]); |
| 153 | |
| 154 | if (\strlen($configuration['exclude_id'] ?? '') > 5) { |
| 155 | $value = \preg_split('/\r\n|\r|\n/', \trim($configuration['exclude_id'] ?? '')); |
| 156 | |
| 157 | if ($value === FALSE) { |
| 157 | if ($value === FALSE) { |
| 158 | $summary[] = $this->t('Block(s) excluded'); |
| 161 | $summary[] = $this->formatPlural(\count($value), '@count block excluded', '@count blocks excluded by id'); |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | return $summary; |
| 165 | return $summary; |
| 166 | } |
| 59 | public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static { |
| 60 | $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition); |
| 61 | $instance->moduleList = $container->get('extension.list.module'); |
| 62 | |
| 63 | return $instance; |
| 64 | } |
| 72 | 'devel', |
| 73 | 'htmx', |
| 74 | 'shortcut', |
| 75 | ], |
| 76 | 'exclude_id' => '', |
| 77 | 'show' => 'grouped', |
| 78 | 'preview' => TRUE, |
| 79 | ]; |
| 80 | } |
| 342 | $sources = $this->getSources(); |
| 343 | $providers = []; |
| 344 | $modules = $this->moduleList->getAllInstalledInfo(); |
| 345 | |
| 346 | foreach ($sources as $source_data) { |
| 346 | foreach ($sources as $source_data) { |
| 347 | if (!isset($source_data['choices'])) { |
| 348 | continue; |
| 350 | $choices = $source_data['choices']; |
| 351 | |
| 352 | foreach ($choices as $choice) { |
| 352 | foreach ($choices as $choice) { |
| 353 | $provider = $choice['provider'] ?? ''; |
| 354 | |
| 355 | if (!$provider || \in_array($provider, self::HIDE_PROVIDER, TRUE)) { |
| 355 | if (!$provider || \in_array($provider, self::HIDE_PROVIDER, TRUE)) { |
| 355 | if (!$provider || \in_array($provider, self::HIDE_PROVIDER, TRUE)) { |
| 356 | continue; |
| 359 | if (!isset($modules[$provider])) { |
| 361 | continue; |
| 364 | if (!isset($providers[$provider])) { |
| 365 | $providers[$provider] = $modules[$provider]; |
| 366 | $providers[$provider]['count'] = 0; |
| 367 | } |
| 368 | ++$providers[$provider]['count']; |
| 352 | foreach ($choices as $choice) { |
| 353 | $provider = $choice['provider'] ?? ''; |
| 354 | |
| 355 | if (!$provider || \in_array($provider, self::HIDE_PROVIDER, TRUE)) { |
| 356 | continue; |
| 357 | } |
| 358 | |
| 359 | if (!isset($modules[$provider])) { |
| 360 | // If the provider is not a module, skip it. |
| 361 | continue; |
| 362 | } |
| 363 | |
| 364 | if (!isset($providers[$provider])) { |
| 365 | $providers[$provider] = $modules[$provider]; |
| 366 | $providers[$provider]['count'] = 0; |
| 367 | } |
| 368 | ++$providers[$provider]['count']; |
| 346 | foreach ($sources as $source_data) { |
| 347 | if (!isset($source_data['choices'])) { |
| 348 | continue; |
| 349 | } |
| 350 | $choices = $source_data['choices']; |
| 351 | |
| 352 | foreach ($choices as $choice) { |
| 346 | foreach ($sources as $source_data) { |
| 347 | if (!isset($source_data['choices'])) { |
| 348 | continue; |
| 349 | } |
| 350 | $choices = $source_data['choices']; |
| 351 | |
| 352 | foreach ($choices as $choice) { |
| 353 | $provider = $choice['provider'] ?? ''; |
| 354 | |
| 355 | if (!$provider || \in_array($provider, self::HIDE_PROVIDER, TRUE)) { |
| 356 | continue; |
| 357 | } |
| 358 | |
| 359 | if (!isset($modules[$provider])) { |
| 360 | // If the provider is not a module, skip it. |
| 361 | continue; |
| 362 | } |
| 363 | |
| 364 | if (!isset($providers[$provider])) { |
| 365 | $providers[$provider] = $modules[$provider]; |
| 366 | $providers[$provider]['count'] = 0; |
| 367 | } |
| 368 | ++$providers[$provider]['count']; |
| 369 | } |
| 370 | } |
| 371 | |
| 372 | return $providers; |
| 373 | } |
| 322 | $options = []; |
| 323 | |
| 324 | foreach ($this->getProviders() as $provider_id => $provider) { |
| 324 | foreach ($this->getProviders() as $provider_id => $provider) { |
| 324 | foreach ($this->getProviders() as $provider_id => $provider) { |
| 324 | foreach ($this->getProviders() as $provider_id => $provider) { |
| 325 | $params = [ |
| 326 | '@name' => $provider['name'], |
| 327 | '@count' => $provider['count'], |
| 328 | ]; |
| 329 | $options[$provider_id] = $this->formatPlural($provider['count'], '@name (@count block)', '@name (@count blocks)', $params); |
| 330 | } |
| 331 | |
| 332 | return $options; |
| 333 | } |
| 272 | if (!empty($this->sources)) { |
| 273 | return $this->sources; |
| 276 | $definitions = $this->sourceManager->getDefinitionsForPropType('slot', $this->configuration['contexts'] ?? []); |
| 277 | $slot_definition = ['ui_patterns' => ['type_definition' => $this->sourceManager->getSlotPropType()]]; |
| 278 | |
| 279 | foreach ($definitions as $source_id => $definition) { |
| 279 | foreach ($definitions as $source_id => $definition) { |
| 279 | foreach ($definitions as $source_id => $definition) { |
| 280 | // A block is a source for slots but without slots. |
| 281 | if (\is_a($definition['class'], SourceWithSlotsInterface::class, TRUE)) { |
| 282 | continue; |
| 285 | if (\in_array($source_id, self::HIDE_SOURCE, TRUE)) { |
| 286 | continue; |
| 289 | try { |
| 290 | $source = $this->sourceManager->createInstance( |
| 295 | catch (\Throwable $e) { |
| 296 | $this->logger->error('Invalid source found: %message', ['%message' => $e->getMessage()]); |
| 297 | |
| 298 | continue; |
| 302 | 'definition' => $definition, |
| 303 | 'source' => $source, |
| 304 | ]; |
| 305 | |
| 306 | if ($source instanceof SourceWithChoicesInterface) { |
| 279 | foreach ($definitions as $source_id => $definition) { |
| 280 | // A block is a source for slots but without slots. |
| 281 | if (\is_a($definition['class'], SourceWithSlotsInterface::class, TRUE)) { |
| 282 | continue; |
| 283 | } |
| 284 | |
| 285 | if (\in_array($source_id, self::HIDE_SOURCE, TRUE)) { |
| 286 | continue; |
| 287 | } |
| 288 | |
| 289 | try { |
| 290 | $source = $this->sourceManager->createInstance( |
| 291 | $source_id, |
| 292 | SourcePluginBase::buildConfiguration('slot', $slot_definition, ['source' => []], $this->configuration['contexts'] ?? []) |
| 293 | ); |
| 294 | } |
| 295 | catch (\Throwable $e) { |
| 296 | $this->logger->error('Invalid source found: %message', ['%message' => $e->getMessage()]); |
| 297 | |
| 298 | continue; |
| 299 | } |
| 300 | |
| 301 | $this->sources[$source_id] = [ |
| 302 | 'definition' => $definition, |
| 303 | 'source' => $source, |
| 304 | ]; |
| 305 | |
| 306 | if ($source instanceof SourceWithChoicesInterface) { |
| 307 | $this->sources[$source_id]['choices'] = $source->getChoices(); |
| 279 | foreach ($definitions as $source_id => $definition) { |
| 279 | foreach ($definitions as $source_id => $definition) { |
| 280 | // A block is a source for slots but without slots. |
| 281 | if (\is_a($definition['class'], SourceWithSlotsInterface::class, TRUE)) { |
| 282 | continue; |
| 283 | } |
| 284 | |
| 285 | if (\in_array($source_id, self::HIDE_SOURCE, TRUE)) { |
| 286 | continue; |
| 287 | } |
| 288 | |
| 289 | try { |
| 290 | $source = $this->sourceManager->createInstance( |
| 291 | $source_id, |
| 292 | SourcePluginBase::buildConfiguration('slot', $slot_definition, ['source' => []], $this->configuration['contexts'] ?? []) |
| 293 | ); |
| 294 | } |
| 295 | catch (\Throwable $e) { |
| 296 | $this->logger->error('Invalid source found: %message', ['%message' => $e->getMessage()]); |
| 297 | |
| 298 | continue; |
| 299 | } |
| 300 | |
| 301 | $this->sources[$source_id] = [ |
| 302 | 'definition' => $definition, |
| 303 | 'source' => $source, |
| 304 | ]; |
| 305 | |
| 306 | if ($source instanceof SourceWithChoicesInterface) { |
| 307 | $this->sources[$source_id]['choices'] = $source->getChoices(); |
| 308 | } |
| 309 | } |
| 310 | |
| 311 | return $this->sources; |
| 312 | } |