Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
93.86% covered (success)
93.86%
107 / 114
86.21% covered (warning)
86.21%
50 / 58
30.61% covered (danger)
30.61%
15 / 49
33.33% covered (danger)
33.33%
2 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
BlockLibrarySourceHelper
93.86% covered (success)
93.86%
107 / 114
86.21% covered (warning)
86.21%
50 / 58
30.61% covered (danger)
30.61%
15 / 49
33.33% covered (danger)
33.33%
2 / 6
396.81
0.00% covered (danger)
0.00%
0 / 1
 getGroupedChoices
93.33% covered (success)
93.33%
14 / 15
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
4.00
 getChoices
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
11 / 11
28.57% covered (danger)
28.57%
2 / 7
100.00% covered (success)
100.00%
1 / 1
14.11
 isChoiceValid
88.89% covered (warning)
88.89%
8 / 9
87.50% covered (warning)
87.50%
7 / 8
33.33% covered (danger)
33.33%
3 / 9
0.00% covered (danger)
0.00%
0 / 1
16.67
 getSourceGroupLabel
85.00% covered (warning)
85.00%
17 / 20
81.25% covered (warning)
81.25%
13 / 16
33.33% covered (danger)
33.33%
5 / 15
0.00% covered (danger)
0.00%
0 / 1
33.00
 getChoiceGroupLabel
87.50% covered (warning)
87.50%
14 / 16
78.57% covered (warning)
78.57%
11 / 14
36.36% covered (danger)
36.36%
4 / 11
0.00% covered (danger)
0.00%
0 / 1
19.63
 sortGroupedChoices
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\display_builder;
6
7use Drupal\Component\Render\MarkupInterface;
8use Drupal\Core\StringTranslation\TranslatableMarkup;
9use Drupal\Core\Url;
10
11/**
12 * Helper class for block library source handling.
13 */
14class BlockLibrarySourceHelper {
15
16  private const HIDE_BLOCK = [
17    'htmx_loader',
18    'broken',
19    'system_main_block',
20    'page_title_block',
21  ];
22
23  /**
24   * Get the choices grouped by category.
25   *
26   * @param array $sources
27   *   An array of all possible sources.
28   * @param array $exclude_provider
29   *   (Optional) An array of providers to hide.
30   *
31   * @return array
32   *   An array of grouped choices.
33   */
34  public static function getGroupedChoices(array $sources, array $exclude_provider = []): array {
35    $choices = self::getChoices($sources, $exclude_provider);
36    $default_category = (string) new TranslatableMarkup('Others');
37
38    $categories = [];
39
40    foreach ($choices as $choice) {
41      $category = $choice['group'] ?? $default_category;
42
43      if ($category instanceof MarkupInterface) {
44        $category = (string) $category;
45      }
46
47      if (!isset($categories[$category])) {
48        $categories[$category] = [
49          'label' => $category,
50          'choices' => [],
51        ];
52      }
53      $categories[$category]['choices'][] = $choice;
54    }
55    self::sortGroupedChoices($categories);
56
57    return $categories;
58  }
59
60  /**
61   * Get the choices from all sources.
62   *
63   * @param array $sources
64   *   An array of all possible sources.
65   * @param array $exclude_provider
66   *   An array of providers to hide.
67   *
68   * @return array
69   *   An array of choices.
70   */
71  private static function getChoices(array $sources, array $exclude_provider): array {
72    $result_choices = [];
73
74    foreach ($sources as $source_id => $source_data) {
75      $definition = $source_data['definition'];
76      $source = $source_data['source'];
77
78      // If no choices, add the source as a single choice.
79      if (!isset($source_data['choices'])) {
80        $label = $definition['label'] ?? $source_id;
81        $keywords = \sprintf('%s %s %s', $definition['id'], $definition['label'] ?? $source_id, $definition['description'] ?? '');
82
83        $result_choices[] = [
84          'label' => (string) $label,
85          'data' => ['source_id' => $source_id],
86          'keywords' => $keywords,
87          'preview' => FALSE,
88          'group' => self::getSourceGroupLabel($definition),
89        ];
90
91        continue;
92      }
93
94      // Mostly for block source, iterate over choices.
95      $choices = $source_data['choices'];
96
97      foreach ($choices as $choice_id => $choice) {
98        if (!self::isChoiceValid($choice, $definition, $exclude_provider)) {
99          continue;
100        }
101
102        $label = $choice['label'] ?? $choice_id;
103        $keywords = \sprintf('%s %s %s %s', $definition['id'], $label, $definition['description'] ?? '', $choice_id);
104        $preview_url = Url::fromRoute('display_builder.api_block_preview', ['block_id' => $choice_id]);
105
106        $result_choices[] = [
107          'label' => (string) $label,
108          'keywords' => $keywords,
109          'data' => [
110            'source_id' => $source_id,
111            'source' => $source->getChoiceSettings($choice_id),
112          ],
113          'preview' => $preview_url,
114          'group' => self::getChoiceGroupLabel($choice, $definition),
115        ];
116      }
117    }
118
119    return $result_choices;
120  }
121
122  /**
123   * Validate a choice against the source definition and allowed providers.
124   *
125   * @param array $choice
126   *   The choice to validate.
127   * @param array $source_definition
128   *   The source definition.
129   * @param array $exclude_provider
130   *   The excluded providers.
131   *
132   * @return bool
133   *   Whether the choice is valid or not.
134   */
135  private static function isChoiceValid(array &$choice, array &$source_definition, array $exclude_provider = []): bool {
136    $provider = $choice['provider'] ?? '';
137
138    if ($provider) {
139      if (\in_array($provider, $exclude_provider, TRUE)) {
140        return FALSE;
141      }
142    }
143
144    if ($source_definition['id'] === 'block') {
145      $block_id = $choice['original_id'] ?? '';
146
147      if ($block_id && \in_array($block_id, self::HIDE_BLOCK, TRUE)) {
148        return FALSE;
149      }
150    }
151
152    return TRUE;
153  }
154
155  /**
156   * Get the group label for a source.
157   *
158   * @param array $source_definition
159   *   The source definition to use for the group.
160   *
161   * @return string
162   *   The group label for the choice.
163   */
164  private static function getSourceGroupLabel(array $source_definition): string {
165    $group = (string) new TranslatableMarkup('Others');
166
167    $provider = $source_definition['provider'] ?? NULL;
168
169    if (!$provider) {
170      return $group;
171    }
172
173    switch ($provider) {
174      case 'display_builder_page_layout':
175        $group = (string) new TranslatableMarkup('Page');
176
177        break;
178
179      case 'display_builder_views':
180      case 'ui_patterns_views':
181        $group = (string) new TranslatableMarkup('Views');
182
183        break;
184
185      case 'display_builder_dev_tools':
186        $group = (string) new TranslatableMarkup('Dev tools');
187
188        break;
189
190      case 'ui_icons_patterns':
191      case 'ui_patterns':
192        $group = (string) new TranslatableMarkup('Utilities');
193
194        break;
195
196      default:
197        break;
198    }
199
200    return $group;
201  }
202
203  /**
204   * Get the group label for a choice.
205   *
206   * @param array $choice
207   *   The choice to get the group for.
208   * @param array $source_definition
209   *   The source definition to use for the group.
210   *
211   * @return string
212   *   The group label for the choice.
213   */
214  private static function getChoiceGroupLabel(array $choice, array $source_definition): string {
215    $group = (string) new TranslatableMarkup('Others');
216    $source_id = $source_definition['id'] ?? NULL;
217
218    if (!$source_id) {
219      return $group;
220    }
221
222    switch ($source_id) {
223      case 'block':
224        if (!empty($choice['group'])) {
225          $group = $choice['group'];
226        }
227
228        break;
229
230      case 'entity_reference':
231        $group = (string) new TranslatableMarkup('Referenced entities');
232
233        break;
234
235      case 'entity_field':
236        $group = (string) new TranslatableMarkup('Fields');
237
238        break;
239
240      default:
241        break;
242    }
243
244    return $group;
245  }
246
247  /**
248   * Sorts the grouped choices based on arbitrary weight.
249   *
250   * @param array $categories
251   *   The categories to sort, passed by reference.
252   */
253  private static function sortGroupedChoices(array &$categories): void {
254    $category_weight = [
255      // Different builder contexts.
256      (string) new TranslatableMarkup('Page') => 1,
257      (string) new TranslatableMarkup('Views') => 1,
258      (string) new TranslatableMarkup('Fields') => 1,
259      (string) new TranslatableMarkup('Referenced entities') => 2,
260      // Global categories.
261      (string) new TranslatableMarkup('Menus') => 3,
262      (string) new TranslatableMarkup('System') => 3,
263      (string) new TranslatableMarkup('User') => 3,
264      (string) new TranslatableMarkup('Utilities') => 3,
265      (string) new TranslatableMarkup('Forms') => 4,
266      (string) new TranslatableMarkup('Lists (Views)') => 5,
267      (string) new TranslatableMarkup('Others') => 6,
268      (string) new TranslatableMarkup('Dev tools') => 99,
269    ];
270
271    // Sort categories by predefined weight, then by natural string comparison
272    // of labels.
273    \uasort($categories, static function ($a, $b) use ($category_weight) {
274      $weight_a = $category_weight[$a['label']] ?? 98;
275      $weight_b = $category_weight[$b['label']] ?? 98;
276
277      if ($weight_a === $weight_b) {
278        return \strnatcmp($a['label'], $b['label']);
279      }
280
281      return $weight_a <=> $weight_b;
282    });
283  }
284
285}

Branches

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.

BlockLibrarySourceHelper->getChoiceGroupLabel
214  private static function getChoiceGroupLabel(array $choice, array $source_definition): string {
215    $group = (string) new TranslatableMarkup('Others');
216    $source_id = $source_definition['id'] ?? NULL;
217
218    if (!$source_id) {
219      return $group;
222    switch ($source_id) {
223      case 'block':
230      case 'entity_reference':
235      case 'entity_field':
235      case 'entity_field':
224        if (!empty($choice['group'])) {
225          $group = $choice['group'];
226        }
227
228        break;
228        break;
231        $group = (string) new TranslatableMarkup('Referenced entities');
232
233        break;
236        $group = (string) new TranslatableMarkup('Fields');
237
238        break;
241        break;
242    }
243
244    return $group;
244    return $group;
BlockLibrarySourceHelper->getChoices
71  private static function getChoices(array $sources, array $exclude_provider): array {
72    $result_choices = [];
73
74    foreach ($sources as $source_id => $source_data) {
74    foreach ($sources as $source_id => $source_data) {
74    foreach ($sources as $source_id => $source_data) {
75      $definition = $source_data['definition'];
76      $source = $source_data['source'];
77
78      // If no choices, add the source as a single choice.
79      if (!isset($source_data['choices'])) {
80        $label = $definition['label'] ?? $source_id;
81        $keywords = \sprintf('%s %s %s', $definition['id'], $definition['label'] ?? $source_id, $definition['description'] ?? '');
82
83        $result_choices[] = [
84          'label' => (string) $label,
85          'data' => ['source_id' => $source_id],
86          'keywords' => $keywords,
87          'preview' => FALSE,
88          'group' => self::getSourceGroupLabel($definition),
89        ];
90
91        continue;
95      $choices = $source_data['choices'];
96
97      foreach ($choices as $choice_id => $choice) {
97      foreach ($choices as $choice_id => $choice) {
97      foreach ($choices as $choice_id => $choice) {
98        if (!self::isChoiceValid($choice, $definition, $exclude_provider)) {
99          continue;
97      foreach ($choices as $choice_id => $choice) {
98        if (!self::isChoiceValid($choice, $definition, $exclude_provider)) {
99          continue;
100        }
101
102        $label = $choice['label'] ?? $choice_id;
74    foreach ($sources as $source_id => $source_data) {
75      $definition = $source_data['definition'];
76      $source = $source_data['source'];
77
78      // If no choices, add the source as a single choice.
79      if (!isset($source_data['choices'])) {
80        $label = $definition['label'] ?? $source_id;
81        $keywords = \sprintf('%s %s %s', $definition['id'], $definition['label'] ?? $source_id, $definition['description'] ?? '');
82
83        $result_choices[] = [
84          'label' => (string) $label,
85          'data' => ['source_id' => $source_id],
86          'keywords' => $keywords,
87          'preview' => FALSE,
88          'group' => self::getSourceGroupLabel($definition),
89        ];
90
91        continue;
92      }
93
94      // Mostly for block source, iterate over choices.
95      $choices = $source_data['choices'];
96
97      foreach ($choices as $choice_id => $choice) {
74    foreach ($sources as $source_id => $source_data) {
75      $definition = $source_data['definition'];
76      $source = $source_data['source'];
77
78      // If no choices, add the source as a single choice.
79      if (!isset($source_data['choices'])) {
80        $label = $definition['label'] ?? $source_id;
81        $keywords = \sprintf('%s %s %s', $definition['id'], $definition['label'] ?? $source_id, $definition['description'] ?? '');
82
83        $result_choices[] = [
84          'label' => (string) $label,
85          'data' => ['source_id' => $source_id],
86          'keywords' => $keywords,
87          'preview' => FALSE,
88          'group' => self::getSourceGroupLabel($definition),
89        ];
90
91        continue;
92      }
93
94      // Mostly for block source, iterate over choices.
95      $choices = $source_data['choices'];
96
97      foreach ($choices as $choice_id => $choice) {
98        if (!self::isChoiceValid($choice, $definition, $exclude_provider)) {
99          continue;
100        }
101
102        $label = $choice['label'] ?? $choice_id;
103        $keywords = \sprintf('%s %s %s %s', $definition['id'], $label, $definition['description'] ?? '', $choice_id);
104        $preview_url = Url::fromRoute('display_builder.api_block_preview', ['block_id' => $choice_id]);
105
106        $result_choices[] = [
107          'label' => (string) $label,
108          'keywords' => $keywords,
109          'data' => [
110            'source_id' => $source_id,
111            'source' => $source->getChoiceSettings($choice_id),
112          ],
113          'preview' => $preview_url,
114          'group' => self::getChoiceGroupLabel($choice, $definition),
115        ];
116      }
117    }
118
119    return $result_choices;
BlockLibrarySourceHelper->getGroupedChoices
34  public static function getGroupedChoices(array $sources, array $exclude_provider = []): array {
35    $choices = self::getChoices($sources, $exclude_provider);
36    $default_category = (string) new TranslatableMarkup('Others');
37
38    $categories = [];
39
40    foreach ($choices as $choice) {
40    foreach ($choices as $choice) {
41      $category = $choice['group'] ?? $default_category;
42
43      if ($category instanceof MarkupInterface) {
44        $category = (string) $category;
45      }
46
47      if (!isset($categories[$category])) {
47      if (!isset($categories[$category])) {
49          'label' => $category,
50          'choices' => [],
51        ];
52      }
53      $categories[$category]['choices'][] = $choice;
40    foreach ($choices as $choice) {
41      $category = $choice['group'] ?? $default_category;
42
43      if ($category instanceof MarkupInterface) {
44        $category = (string) $category;
45      }
46
47      if (!isset($categories[$category])) {
48        $categories[$category] = [
49          'label' => $category,
50          'choices' => [],
51        ];
52      }
53      $categories[$category]['choices'][] = $choice;
40    foreach ($choices as $choice) {
41      $category = $choice['group'] ?? $default_category;
42
43      if ($category instanceof MarkupInterface) {
44        $category = (string) $category;
45      }
46
47      if (!isset($categories[$category])) {
48        $categories[$category] = [
49          'label' => $category,
50          'choices' => [],
51        ];
52      }
53      $categories[$category]['choices'][] = $choice;
54    }
55    self::sortGroupedChoices($categories);
56
57    return $categories;
BlockLibrarySourceHelper->getSourceGroupLabel
164  private static function getSourceGroupLabel(array $source_definition): string {
165    $group = (string) new TranslatableMarkup('Others');
166
167    $provider = $source_definition['provider'] ?? NULL;
168
169    if (!$provider) {
170      return $group;
173    switch ($provider) {
174      case 'display_builder_page_layout':
179      case 'display_builder_views':
180      case 'ui_patterns_views':
185      case 'display_builder_dev_tools':
190      case 'ui_icons_patterns':
191      case 'ui_patterns':
191      case 'ui_patterns':
175        $group = (string) new TranslatableMarkup('Page');
176
177        break;
181        $group = (string) new TranslatableMarkup('Views');
182
183        break;
186        $group = (string) new TranslatableMarkup('Dev tools');
187
188        break;
192        $group = (string) new TranslatableMarkup('Utilities');
193
194        break;
197        break;
198    }
199
200    return $group;
200    return $group;
BlockLibrarySourceHelper->isChoiceValid
135  private static function isChoiceValid(array &$choice, array &$source_definition, array $exclude_provider = []): bool {
136    $provider = $choice['provider'] ?? '';
137
138    if ($provider) {
139      if (\in_array($provider, $exclude_provider, TRUE)) {
140        return FALSE;
144    if ($source_definition['id'] === 'block') {
145      $block_id = $choice['original_id'] ?? '';
146
147      if ($block_id && \in_array($block_id, self::HIDE_BLOCK, TRUE)) {
147      if ($block_id && \in_array($block_id, self::HIDE_BLOCK, TRUE)) {
148        return FALSE;
152    return TRUE;
BlockLibrarySourceHelper->sortGroupedChoices
253  private static function sortGroupedChoices(array &$categories): void {
254    $category_weight = [
255      // Different builder contexts.
256      (string) new TranslatableMarkup('Page') => 1,
257      (string) new TranslatableMarkup('Views') => 1,
258      (string) new TranslatableMarkup('Fields') => 1,
259      (string) new TranslatableMarkup('Referenced entities') => 2,
260      // Global categories.
261      (string) new TranslatableMarkup('Menus') => 3,
262      (string) new TranslatableMarkup('System') => 3,
263      (string) new TranslatableMarkup('User') => 3,
264      (string) new TranslatableMarkup('Utilities') => 3,
265      (string) new TranslatableMarkup('Forms') => 4,
266      (string) new TranslatableMarkup('Lists (Views)') => 5,
267      (string) new TranslatableMarkup('Others') => 6,
268      (string) new TranslatableMarkup('Dev tools') => 99,
269    ];
270
271    // Sort categories by predefined weight, then by natural string comparison
272    // of labels.
273    \uasort($categories, static function ($a, $b) use ($category_weight) {
274      $weight_a = $category_weight[$a['label']] ?? 98;
275      $weight_b = $category_weight[$b['label']] ?? 98;
276
277      if ($weight_a === $weight_b) {
278        return \strnatcmp($a['label'], $b['label']);
279      }
280
281      return $weight_a <=> $weight_b;
282    });
283  }
{closure:/var/www/html/web/modules/custom/display_builder/src/BlockLibrarySourceHelper.php:273-282}
273    \uasort($categories, static function ($a, $b) use ($category_weight) {
274      $weight_a = $category_weight[$a['label']] ?? 98;
275      $weight_b = $category_weight[$b['label']] ?? 98;
276
277      if ($weight_a === $weight_b) {
278        return \strnatcmp($a['label'], $b['label']);
281      return $weight_a <=> $weight_b;