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