Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
29.03% covered (danger)
29.03%
9 / 31
13.33% covered (danger)
13.33%
2 / 15
8.70% covered (danger)
8.70%
2 / 23
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
DisplayBuilderSubscriber
29.03% covered (danger)
29.03%
9 / 31
13.33% covered (danger)
13.33%
2 / 15
8.70% covered (danger)
8.70%
2 / 23
50.00% covered (danger)
50.00%
2 / 4
56.71
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%
3 / 3
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
 onRevert
26.32% covered (danger)
26.32%
5 / 19
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
15.00
 getEntityViewDisplayEntity
0.00% covered (danger)
0.00%
0 / 8
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
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\display_builder_entity_view\EventSubscriber;
6
7use Drupal\Core\Entity\Display\EntityDisplayInterface;
8use Drupal\Core\Entity\EntityTypeManagerInterface;
9use Drupal\Core\Entity\FieldableEntityInterface;
10use Drupal\Core\Plugin\Context\ContextInterface;
11use Drupal\display_builder\Event\DisplayBuilderEvent;
12use Drupal\display_builder\Event\DisplayBuilderEvents;
13use Drupal\display_builder_entity_view\Plugin\display_builder\Buildable\EntityViewOverride;
14use Symfony\Component\EventDispatcher\EventSubscriberInterface;
15
16/**
17 * The event subscriber for display builder islands.
18 */
19class DisplayBuilderSubscriber implements EventSubscriberInterface {
20
21  public function __construct(
22    protected EntityTypeManagerInterface $entityTypeManager,
23  ) {}
24
25  /**
26   * {@inheritdoc}
27   */
28  public static function getSubscribedEvents(): array {
29    return [
30      DisplayBuilderEvents::ON_REVERT => 'onRevert',
31    ];
32  }
33
34  /**
35   * Event handler for when a display builder override is reverted.
36   *
37   * Clears the entity field override, then reloads sources from the base
38   * entity view display config so the instance reflects the default layout.
39   *
40   * @param \Drupal\display_builder\Event\DisplayBuilderEvent $event
41   *   The event object.
42   */
43  public function onRevert(DisplayBuilderEvent $event): void {
44    $instance = $event->getInstance();
45    $instance_id = (string) $instance->id();
46    $instanceInfos = EntityViewOverride::checkInstanceId($instance_id);
47
48    if (!isset($instanceInfos['entity_type_id'], $instanceInfos['entity_id'], $instanceInfos['field_name'])) {
49      return;
50    }
51
52    // Do not get the profile entity ID from Instance context because the
53    // data stored there is not reliable yet.
54    // See: https://www.drupal.org/project/display_builder/issues/3544545
55    $entity = $this->entityTypeManager->getStorage($instanceInfos['entity_type_id'])
56      ->load($instanceInfos['entity_id']);
57
58    if (!$entity instanceof FieldableEntityInterface) {
59      return;
60    }
61
62    // Remove the saved state as the field values will be deleted.
63    $instance->setNewPresent([], 'Revert 1/2: clear overridden data and save');
64    $instance->save();
65
66    // Clear field value.
67    $entity->get($instanceInfos['field_name'])->setValue(NULL);
68    $entity->save();
69
70    $config = $instance->get('buildable')->first()->get('configuration')->getValue();
71
72    if (isset($config['display_id'])) {
73      /** @var \Drupal\display_builder\DisplayBuildableInterface|null $display */
74      $display = $this->entityTypeManager->getStorage('entity_view_display')->load($config['display_id']);
75
76      if ($display) {
77        $instance->setNewPresent($display->getSources(), 'Revert 2/2: retrieve existing data from config');
78        $instance->save();
79      }
80    }
81  }
82
83  /**
84   * Get entity view display entity.
85   *
86   * @param \Drupal\Core\Plugin\Context\ContextInterface $entity_context
87   *   The entity context.
88   * @param \Drupal\Core\Plugin\Context\ContextInterface $view_mode_context
89   *   The view mode context.
90   *
91   * @return \Drupal\Core\Entity\Display\EntityDisplayInterface|null
92   *   The entity view display entity or NULL if not found.
93   */
94  protected function getEntityViewDisplayEntity(ContextInterface $entity_context, ContextInterface $view_mode_context): ?EntityDisplayInterface {
95    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
96    $entity = $entity_context->getContextValue();
97    $entity_type_id = $entity->getEntityTypeId();
98    $bundle = $entity->bundle();
99    $view_mode = $view_mode_context->getContextValue();
100    $display_id = "{$entity_type_id}.{$bundle}.{$view_mode}";
101
102    /** @var \Drupal\Core\Entity\Display\EntityDisplayInterface|null $display */
103    $display = $this->entityTypeManager->getStorage('entity_view_display')
104      ->load($display_id);
105
106    return $display;
107  }
108
109}