Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 101
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
TreePanel
0.00% covered (danger)
0.00%
0 / 94
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 5
240
0.00% covered (danger)
0.00%
0 / 1
 create
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 keyboardShortcuts
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 build
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 buildSingleComponent
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 1
72
 buildSingleBlock
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\display_builder\Plugin\display_builder\Island;
6
7use Drupal\Core\StringTranslation\TranslatableMarkup;
8use Drupal\display_builder\Attribute\Island;
9use Drupal\display_builder\InstanceInterface;
10use Drupal\display_builder\IslandType;
11use Drupal\display_builder\SlotSourceProxy;
12use Drupal\display_builder\SourceWithSlotsInterface;
13use Drupal\ui_patterns\SourceWithChoicesInterface;
14use Symfony\Component\DependencyInjection\ContainerInterface;
15
16/**
17 * Layers island plugin implementation.
18 */
19#[Island(
20  id: 'tree',
21  label: new TranslatableMarkup('Tree'),
22  description: new TranslatableMarkup('Hierarchical view of components and blocks.'),
23  type: IslandType::View,
24  default_region: 'main',
25  icon: 'bar-chart-steps',
26)]
27class TreePanel extends BuilderPanel {
28
29  /**
30   * Proxy for slot source operations.
31   */
32  protected SlotSourceProxy $slotSourceProxy;
33
34  /**
35   * {@inheritdoc}
36   */
37  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
38    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
39    $instance->slotSourceProxy = $container->get('display_builder.slot_sources_proxy');
40
41    return $instance;
42  }
43
44  /**
45   * {@inheritdoc}
46   */
47  public static function keyboardShortcuts(): array {
48    return [
49      'key' => 't',
50      'help' => t('Show the tree'),
51    ];
52  }
53
54  /**
55   * {@inheritdoc}
56   */
57  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
58    $builder_id = (string) $builder->id();
59
60    $build = [
61      '#type' => 'component',
62      '#component' => 'display_builder:panel_tree',
63      '#slots' => [
64        'items' => $this->digFromSlot($builder_id, $data),
65      ],
66      '#attributes' => [
67        // Required for JavaScript @see components/dropzone/dropzone.js.
68        'data-db-id' => $builder_id,
69        'data-node-title' => $this->t('Base container'),
70        'data-db-root' => TRUE,
71        // 'class' => ['db-dropzone--root', 'db-dropzone'],
72      ],
73    ];
74
75    return $build;
76  }
77
78  /**
79   * {@inheritdoc}
80   */
81  protected function buildSingleComponent(string $builder_id, string $instance_id, SourceWithSlotsInterface $source, array $data, int $index = 0): ?array {
82    $component_id = $source->getPluginId();
83    $label = $source->label();
84
85    if ($source instanceof SourceWithChoicesInterface) {
86      $component_id = $source->getChoice($data['source']);
87      $label = $this->slotSourceProxy->getLabelWithSummary($data, [])['label'];
88    }
89    $instance_id = $instance_id ?: $data['node_id'];
90
91    if (!$instance_id || !$component_id) {
92      return NULL;
93    }
94
95    $slots = [];
96
97    foreach ($source->getSlotDefinitions() as $slot_id => $definition) {
98      $items = [
99        '#type' => 'component',
100        '#component' => 'display_builder:tree_item',
101        '#props' => [
102          'icon' => 'box-arrow-in-right',
103        ],
104        '#slots' => [
105          'title' => $definition['title'],
106        ],
107        // Slot is needed for contextual menu paste.
108        // @see assets/js/contextual_menu.js
109        '#attributes' => [
110          'data-slot-id' => $slot_id,
111          'data-slot-title' => $definition['title'],
112          'data-node-id' => $instance_id,
113          'data-node-title' => $label,
114          'data-menu-type' => 'slot',
115        ],
116      ];
117
118      if ($sources = $source->getSlotValue($slot_id)) {
119        $items['#slots']['children'] = $this->digFromSlot($builder_id, $sources);
120      }
121
122      $slots[] = $items;
123    }
124
125    // I f a single item, expand by default.
126    if (\count($slots) === 1) {
127      $slots[0]['#props']['expanded'] = TRUE;
128    }
129
130    return [
131      '#type' => 'component',
132      '#component' => 'display_builder:tree_item',
133      '#props' => [
134        'expanded' => TRUE,
135        'icon' => 'box',
136      ],
137      '#slots' => [
138        'title' => $label,
139        'children' => $slots,
140      ],
141      // Required for the context menu label.
142      // @see assets/js/contextual_menu.js
143      '#attributes' => [
144        'data-node-id' => $instance_id,
145        'data-node-title' => $label,
146        'data-slot-position' => $index,
147        'data-menu-type' => 'component',
148        // 'class' => ['db-dropzone', 'db-tree__component'],
149      ],
150    ];
151  }
152
153  /**
154   * {@inheritdoc}
155   */
156  protected function buildSingleBlock(string $builder_id, string $instance_id, array $data, int $index = 0): array {
157    $instance_id = $instance_id ?: $data['node_id'];
158    $label = $this->slotSourceProxy->getLabelWithSummary($data, $this->configuration['contexts'] ?? []);
159
160    if (isset($data['source_id']) && $data['source_id'] === 'entity_field') {
161      $label['summary'] = (string) $this->t('Field: @label', ['@label' => $label['label']]);
162    }
163
164    return [
165      '#type' => 'component',
166      '#component' => 'display_builder:tree_item',
167      '#props' => [
168        'icon' => 'view-list',
169      ],
170      '#slots' => [
171        'title' => $label['summary'],
172      ],
173      '#attributes' => [
174        'data-node-id' => $instance_id,
175        // This label is used for contextual menu.
176        // @see assets/js/contextual_menu.js
177        'data-node-title' => $label['summary'],
178        'data-slot-position' => $index,
179        'data-menu-type' => 'block',
180        // 'class' => ['db-dropzone', 'db-tree__block'],
181      ],
182    ];
183  }
184
185}

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.

TreePanel->build
57  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
58    $builder_id = (string) $builder->id();
59
60    $build = [
61      '#type' => 'component',
62      '#component' => 'display_builder:panel_tree',
63      '#slots' => [
64        'items' => $this->digFromSlot($builder_id, $data),
65      ],
66      '#attributes' => [
67        // Required for JavaScript @see components/dropzone/dropzone.js.
68        'data-db-id' => $builder_id,
69        'data-node-title' => $this->t('Base container'),
70        'data-db-root' => TRUE,
71        // 'class' => ['db-dropzone--root', 'db-dropzone'],
72      ],
73    ];
74
75    return $build;
76  }
TreePanel->buildSingleBlock
156  protected function buildSingleBlock(string $builder_id, string $instance_id, array $data, int $index = 0): array {
157    $instance_id = $instance_id ?: $data['node_id'];
158    $label = $this->slotSourceProxy->getLabelWithSummary($data, $this->configuration['contexts'] ?? []);
159
160    if (isset($data['source_id']) && $data['source_id'] === 'entity_field') {
160    if (isset($data['source_id']) && $data['source_id'] === 'entity_field') {
160    if (isset($data['source_id']) && $data['source_id'] === 'entity_field') {
161      $label['summary'] = (string) $this->t('Field: @label', ['@label' => $label['label']]);
162    }
163
164    return [
165      '#type' => 'component',
165      '#type' => 'component',
166      '#component' => 'display_builder:tree_item',
167      '#props' => [
168        'icon' => 'view-list',
169      ],
170      '#slots' => [
171        'title' => $label['summary'],
172      ],
173      '#attributes' => [
174        'data-node-id' => $instance_id,
175        // This label is used for contextual menu.
176        // @see assets/js/contextual_menu.js
177        'data-node-title' => $label['summary'],
178        'data-slot-position' => $index,
179        'data-menu-type' => 'block',
180        // 'class' => ['db-dropzone', 'db-tree__block'],
181      ],
182    ];
183  }
TreePanel->buildSingleComponent
81  protected function buildSingleComponent(string $builder_id, string $instance_id, SourceWithSlotsInterface $source, array $data, int $index = 0): ?array {
82    $component_id = $source->getPluginId();
83    $label = $source->label();
84
85    if ($source instanceof SourceWithChoicesInterface) {
86      $component_id = $source->getChoice($data['source']);
87      $label = $this->slotSourceProxy->getLabelWithSummary($data, [])['label'];
88    }
89    $instance_id = $instance_id ?: $data['node_id'];
89    $instance_id = $instance_id ?: $data['node_id'];
90
91    if (!$instance_id || !$component_id) {
91    if (!$instance_id || !$component_id) {
91    if (!$instance_id || !$component_id) {
92      return NULL;
95    $slots = [];
96
97    foreach ($source->getSlotDefinitions() as $slot_id => $definition) {
97    foreach ($source->getSlotDefinitions() as $slot_id => $definition) {
97    foreach ($source->getSlotDefinitions() as $slot_id => $definition) {
98      $items = [
99        '#type' => 'component',
100        '#component' => 'display_builder:tree_item',
101        '#props' => [
102          'icon' => 'box-arrow-in-right',
103        ],
104        '#slots' => [
105          'title' => $definition['title'],
106        ],
107        // Slot is needed for contextual menu paste.
108        // @see assets/js/contextual_menu.js
109        '#attributes' => [
110          'data-slot-id' => $slot_id,
111          'data-slot-title' => $definition['title'],
112          'data-node-id' => $instance_id,
113          'data-node-title' => $label,
114          'data-menu-type' => 'slot',
115        ],
116      ];
117
118      if ($sources = $source->getSlotValue($slot_id)) {
119        $items['#slots']['children'] = $this->digFromSlot($builder_id, $sources);
120      }
121
122      $slots[] = $items;
97    foreach ($source->getSlotDefinitions() as $slot_id => $definition) {
98      $items = [
99        '#type' => 'component',
100        '#component' => 'display_builder:tree_item',
101        '#props' => [
102          'icon' => 'box-arrow-in-right',
103        ],
104        '#slots' => [
105          'title' => $definition['title'],
106        ],
107        // Slot is needed for contextual menu paste.
108        // @see assets/js/contextual_menu.js
109        '#attributes' => [
110          'data-slot-id' => $slot_id,
111          'data-slot-title' => $definition['title'],
112          'data-node-id' => $instance_id,
113          'data-node-title' => $label,
114          'data-menu-type' => 'slot',
115        ],
116      ];
117
118      if ($sources = $source->getSlotValue($slot_id)) {
119        $items['#slots']['children'] = $this->digFromSlot($builder_id, $sources);
120      }
121
122      $slots[] = $items;
97    foreach ($source->getSlotDefinitions() as $slot_id => $definition) {
98      $items = [
99        '#type' => 'component',
100        '#component' => 'display_builder:tree_item',
101        '#props' => [
102          'icon' => 'box-arrow-in-right',
103        ],
104        '#slots' => [
105          'title' => $definition['title'],
106        ],
107        // Slot is needed for contextual menu paste.
108        // @see assets/js/contextual_menu.js
109        '#attributes' => [
110          'data-slot-id' => $slot_id,
111          'data-slot-title' => $definition['title'],
112          'data-node-id' => $instance_id,
113          'data-node-title' => $label,
114          'data-menu-type' => 'slot',
115        ],
116      ];
117
118      if ($sources = $source->getSlotValue($slot_id)) {
119        $items['#slots']['children'] = $this->digFromSlot($builder_id, $sources);
120      }
121
122      $slots[] = $items;
123    }
124
125    // I f a single item, expand by default.
126    if (\count($slots) === 1) {
127      $slots[0]['#props']['expanded'] = TRUE;
128    }
129
130    return [
131      '#type' => 'component',
131      '#type' => 'component',
132      '#component' => 'display_builder:tree_item',
133      '#props' => [
134        'expanded' => TRUE,
135        'icon' => 'box',
136      ],
137      '#slots' => [
138        'title' => $label,
139        'children' => $slots,
140      ],
141      // Required for the context menu label.
142      // @see assets/js/contextual_menu.js
143      '#attributes' => [
144        'data-node-id' => $instance_id,
145        'data-node-title' => $label,
146        'data-slot-position' => $index,
147        'data-menu-type' => 'component',
148        // 'class' => ['db-dropzone', 'db-tree__component'],
149      ],
150    ];
151  }
TreePanel->create
37  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
38    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
39    $instance->slotSourceProxy = $container->get('display_builder.slot_sources_proxy');
40
41    return $instance;
42  }
TreePanel->keyboardShortcuts
49      'key' => 't',
50      'help' => t('Show the tree'),
51    ];
52  }