Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
29.73% covered (danger)
29.73%
11 / 37
8.33% covered (danger)
8.33%
1 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
DisplayBuilderEventsSubscriber
29.73% covered (danger)
29.73%
11 / 37
8.33% covered (danger)
8.33%
1 / 12
117.28
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSubscribedEvents
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 onActive
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onAttachToRoot
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onAttachToSlot
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onDelete
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onHistoryChange
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onMove
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onUpdate
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onSave
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onPresetSave
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 dispatchToIslands
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\display_builder\Event;
6
7use Drupal\Core\Entity\EntityTypeManagerInterface;
8use Drupal\display_builder\IslandPluginManagerInterface;
9use Symfony\Component\EventDispatcher\EventSubscriberInterface;
10
11/**
12 * The event subscriber for display builder islands.
13 */
14class DisplayBuilderEventsSubscriber implements EventSubscriberInterface {
15
16  /**
17   * Constructs a new ApiController object.
18   *
19   * @param \Drupal\display_builder\IslandPluginManagerInterface $islandManager
20   *   The island plugin manager.
21   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
22   *   The entity type manager service.
23   */
24  public function __construct(
25    protected IslandPluginManagerInterface $islandManager,
26    protected EntityTypeManagerInterface $entityTypeManager,
27  ) {}
28
29  /**
30   * {@inheritdoc}
31   */
32  public static function getSubscribedEvents(): array {
33    return [
34      DisplayBuilderEvents::ON_ACTIVE => 'onActive',
35      DisplayBuilderEvents::ON_ATTACH_TO_ROOT => 'onAttachToRoot',
36      DisplayBuilderEvents::ON_ATTACH_TO_SLOT => 'onAttachToSlot',
37      DisplayBuilderEvents::ON_DELETE => 'onDelete',
38      DisplayBuilderEvents::ON_HISTORY_CHANGE => 'onHistoryChange',
39      DisplayBuilderEvents::ON_MOVE => 'onMove',
40      DisplayBuilderEvents::ON_UPDATE => 'onUpdate',
41      DisplayBuilderEvents::ON_SAVE => 'onSave',
42      DisplayBuilderEvents::ON_PRESET_SAVE => 'onPresetSave',
43    ];
44  }
45
46  /**
47   * Event handler for when a block becomes active.
48   *
49   * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event
50   *   The event object.
51   */
52  public function onActive(DisplayBuilderEvent $event): void {
53    $this->dispatchToIslands($event, __FUNCTION__, [$event->getData()]);
54  }
55
56  /**
57   * Event handler for when a block is attached to the root.
58   *
59   * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event
60   *   The event object.
61   */
62  public function onAttachToRoot(DisplayBuilderEvent $event): void {
63    $this->dispatchToIslands($event, __FUNCTION__, [$event->getInstanceId()]);
64  }
65
66  /**
67   * Event handler for when a block is attached to a slot.
68   *
69   * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event
70   *   The event object.
71   */
72  public function onAttachToSlot(DisplayBuilderEvent $event): void {
73    $this->dispatchToIslands($event, __FUNCTION__, [$event->getInstanceId(), $event->getParentId()]);
74  }
75
76  /**
77   * Event handler for when a block is deleted.
78   *
79   * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event
80   *   The event object.
81   */
82  public function onDelete(DisplayBuilderEvent $event): void {
83    $this->dispatchToIslands($event, __FUNCTION__, [$event->getParentId()]);
84  }
85
86  /**
87   * Event handler for when the history changes.
88   *
89   * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event
90   *   The event object.
91   */
92  public function onHistoryChange(DisplayBuilderEvent $event): void {
93    $this->dispatchToIslands($event, __FUNCTION__);
94  }
95
96  /**
97   * Event handler for when a block is moved.
98   *
99   * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event
100   *   The event object.
101   */
102  public function onMove(DisplayBuilderEvent $event): void {
103    $this->dispatchToIslands($event, __FUNCTION__, [$event->getInstanceId()]);
104  }
105
106  /**
107   * Event handler for when a block is updated.
108   *
109   * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event
110   *   The event object.
111   */
112  public function onUpdate(DisplayBuilderEvent $event): void {
113    $this->dispatchToIslands($event, __FUNCTION__, [$event->getInstanceId(), $event->getCurrentIslandId()]);
114  }
115
116  /**
117   * Event handler for when a display is saved.
118   *
119   * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event
120   *   The event object.
121   */
122  public function onSave(DisplayBuilderEvent $event): void {
123    $this->dispatchToIslands($event, __FUNCTION__, [$event->getData()]);
124  }
125
126  /**
127   * Event handler for when a preset is saved.
128   *
129   * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event
130   *   The event object.
131   */
132  public function onPresetSave(DisplayBuilderEvent $event): void {
133    $this->dispatchToIslands($event, __FUNCTION__);
134  }
135
136  /**
137   * Dispatch the event with a generic code.
138   *
139   * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event
140   *   The event object.
141   * @param string $method
142   *   The method to dispatch.
143   * @param array $parameters
144   *   (Optional) The parameters to the method.
145   */
146  private function dispatchToIslands(DisplayBuilderEvent $event, string $method, array $parameters = []): void {
147    \array_unshift($parameters, $event->getBuilderId());
148
149    $configuration = $event->getIslandConfiguration();
150    /** @var \Drupal\display_builder\InstanceInterface $builder */
151    $builder = $this->entityTypeManager->getStorage('display_builder_instance')->load($event->getBuilderId());
152    $contexts = $builder->getContexts();
153    $islands = $this->islandManager->createInstances($this->islandManager->getDefinitions(), $contexts, $configuration);
154
155    $island_enabled = $event->getEnabledIslands();
156
157    foreach ($islands as $island_id => $island) {
158      if (!isset($island_enabled[$island_id])) {
159        continue;
160      }
161
162      // Skip the island triggering the HTMX event. Useful to avoid swapping
163      // the content of an island which is already in the expected state.
164      // For examples, if we move an instance in Builder, Layers or Tree
165      // panels, if we change the settings in InstanceForm.
166      // @see Drupal\display_builder\Controller\ApiControllerBase::islandId
167      if ($island_id === $event->getCurrentIslandId()) {
168        continue;
169      }
170
171      if (!\method_exists($island, $method)) {
172        continue;
173      }
174      $result = $island->{$method}(...$parameters);
175
176      if ($result !== NULL) {
177        $event->appendResult($island_id, $result);
178      }
179    }
180  }
181
182}