Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
50.94% covered (warning)
50.94%
54 / 106
53.33% covered (warning)
53.33%
40 / 75
24.29% covered (danger)
24.29%
17 / 70
37.50% covered (danger)
37.50%
6 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
EntityViewDisplayTrait
50.94% covered (warning)
50.94%
54 / 106
53.33% covered (warning)
53.33%
40 / 75
24.29% covered (danger)
24.29%
17 / 70
37.50% covered (danger)
37.50%
6 / 16
845.55
0.00% covered (danger)
0.00%
0 / 1
 calculateDependencies
92.31% covered (success)
92.31%
12 / 13
90.00% covered (success)
90.00%
9 / 10
50.00% covered (danger)
50.00%
3 / 6
0.00% covered (danger)
0.00%
0 / 1
8.12
 isDisplayBuilderEnabled
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 onDependencyRemoval
91.67% covered (success)
91.67%
11 / 12
87.50% covered (warning)
87.50%
7 / 8
20.00% covered (danger)
20.00%
1 / 5
0.00% covered (danger)
0.00%
0 / 1
12.19
 getDisplayBuilderOverrideField
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
 getDisplayBuilderOverrideProfile
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 isDisplayBuilderOverridable
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 postSave
61.11% covered (warning)
61.11%
11 / 18
62.50% covered (warning)
62.50%
10 / 16
10.00% covered (danger)
10.00%
3 / 30
0.00% covered (danger)
0.00%
0 / 1
54.66
 delete
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 buildMultiple
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
30
 isOverrideOfCurrentDisplay
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
 getContextsForEntity
0.00% covered (danger)
0.00%
0 / 6
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
 contextRepository
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
 getInstance
100.00% covered (success)
100.00%
4 / 4
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
 displayBuildable
100.00% covered (success)
100.00%
2 / 2
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
 loadDisplayBuilder
80.00% covered (warning)
80.00%
4 / 5
66.67% covered (warning)
66.67%
2 / 3
50.00% covered (danger)
50.00%
1 / 2
0.00% covered (danger)
0.00%
0 / 1
2.50
 buildSources
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\display_builder_entity_view\Entity;
6
7use Drupal\Core\Cache\CacheableMetadata;
8use Drupal\Core\Entity\EntityStorageInterface;
9use Drupal\Core\Entity\FieldableEntityInterface;
10use Drupal\Core\Plugin\Context\Context;
11use Drupal\Core\Plugin\Context\ContextDefinition;
12use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
13use Drupal\Core\Plugin\Context\EntityContext;
14use Drupal\display_builder\DisplayBuildableInterface;
15use Drupal\display_builder\InstanceInterface;
16use Drupal\display_builder\ProfileInterface;
17use Drupal\display_builder_entity_view\Plugin\display_builder\Buildable\EntityViewOverride;
18
19/**
20 * Common methods for entity view display.
21 */
22trait EntityViewDisplayTrait {
23
24  /**
25   * Calculates dependencies for the display builder.
26   *
27   * @return $this
28   *   The current instance.
29   *
30   * @see \Drupal\Core\Entity\Display\EntityViewDisplayInterface
31   */
32  public function calculateDependencies(): self {
33    parent::calculateDependencies();
34
35    if (!$this->displayBuildable()->getInstanceId()) {
36      // If there is no instance ID, we cannot calculate dependencies.
37      return $this;
38    }
39
40    /** @var \Drupal\display_builder\InstanceInterface $instance */
41    $instance = $this->entityTypeManager->getStorage('display_builder_instance')->load($this->displayBuildable()->getInstanceId());
42
43    if (!$instance) {
44      return $this;
45    }
46    $contexts = $instance->getContexts();
47
48    if (!$contexts) {
49      return $this;
50    }
51
52    foreach ($this->displayBuildable()->getSources() as $source_data) {
53      /** @var \Drupal\ui_patterns\SourceInterface $source */
54      $source = $this->sourcePluginManager->getSource('', [], $source_data, $contexts);
55      $this->addDependencies($source->calculateDependencies());
56    }
57
58    return $this;
59  }
60
61  /**
62   * Is display builder enabled?
63   *
64   * @return bool
65   *   The display builder is enabled if there is a Display Builder entity.
66   *
67   * @see \Drupal\display_builder_entity_view\DisplayBuilderEntityDisplayInterface
68   */
69  public function isDisplayBuilderEnabled(): bool {
70    // Display Builder must not be enabled for the '_custom' view mode that is
71    // used for on-the-fly rendering of fields in isolation from the entity.
72    if ($this->getOriginalMode() === static::CUSTOM_MODE) {
73      return FALSE;
74    }
75
76    return (bool) $this->displayBuildable()->getProfile();
77  }
78
79  /**
80   * Handler for when dependencies are removed.
81   *
82   * @param array $dependencies
83   *   The dependencies that were removed.
84   *
85   * @return bool
86   *   TRUE if the display can be overridden, FALSE otherwise.
87   *
88   * @see \Drupal\Core\Entity\Display\EntityViewDisplayInterface
89   */
90  public function onDependencyRemoval(array $dependencies): bool {
91    $changed = parent::onDependencyRemoval($dependencies);
92
93    // Loop through all sources and determine if the removed dependencies are
94    // used by their plugins.
95    /** @var \Drupal\display_builder\InstanceInterface $instance */
96    $instance = $this->getInstance();
97
98    // @todo not working when content entity type is deleted.
99    if (!$instance) {
100      return TRUE;
101    }
102
103    $contexts = $instance->getContexts();
104
105    foreach ($this->displayBuildable()->getSources() as $source_data) {
106      /** @var \Drupal\ui_patterns\SourceInterface $source */
107      $source = $this->sourcePluginManager->getSource('', [], $source_data, $contexts);
108      $source_dependencies = $source->calculateDependencies();
109      $source_removed_dependencies = $this->getPluginRemovedDependencies($source_dependencies, $dependencies);
110
111      if ($source_removed_dependencies) {
112        // @todo Allow the plugins to react to their dependency removal in
113        // https://www.drupal.org/project/drupal/issues/2579743.
114        // $this->removeSource($delta);
115        $changed = TRUE;
116      }
117    }
118
119    return $changed;
120  }
121
122  /**
123   * Returns the field name used to store overridden displays.
124   *
125   * @return string|null
126   *   The field name used to store overridden displays, or NULL if not set.
127   *
128   * @see \Drupal\display_builder_entity_view\Entity\DisplayBuilderOverridableInterface
129   */
130  public function getDisplayBuilderOverrideField(): ?string {
131    return $this->getThirdPartySetting('display_builder', DisplayBuildableInterface::OVERRIDE_FIELD_PROPERTY);
132  }
133
134  /**
135   * Returns the display builder override profile.
136   *
137   * @return \Drupal\display_builder\ProfileInterface|null
138   *   The display builder override profile, or NULL if not set.
139   *
140   * @see \Drupal\display_builder_entity_view\Entity\DisplayBuilderOverridableInterface
141   */
142  public function getDisplayBuilderOverrideProfile(): ?ProfileInterface {
143    $display_builder_id = $this->getThirdPartySetting('display_builder', DisplayBuildableInterface::OVERRIDE_PROFILE_PROPERTY);
144
145    if ($display_builder_id === NULL) {
146      return NULL;
147    }
148
149    return $this->loadDisplayBuilder($display_builder_id);
150  }
151
152  /**
153   * Returns TRUE if the display can be overridden.
154   *
155   * @return bool
156   *   TRUE if the display can be overridden, FALSE otherwise.
157   *
158   * @see \Drupal\display_builder_entity_view\Entity\DisplayBuilderOverridableInterface
159   */
160  public function isDisplayBuilderOverridable(): bool {
161    return !empty($this->getDisplayBuilderOverrideField())
162      && $this->getDisplayBuilderOverrideProfile() !== NULL;
163  }
164
165  /**
166   * Post-save operations for the display builder.
167   *
168   * @param \Drupal\Core\Entity\EntityStorageInterface $storage
169   *   The entity storage.
170   * @param bool $update
171   *   Whether the entity is being updated.
172   *
173   * @see \Drupal\Core\Entity\Display\EntityViewDisplayInterface
174   */
175  public function postSave(EntityStorageInterface $storage, $update = TRUE): void {
176    if ($profile = $this->displayBuildable()->getProfile()) {
177      $this->displayBuildable()->initInstanceIfMissing();
178
179      // Save the profile in the instance if changed.
180      $instance = $this->getInstance();
181      $profile_id = (string) $profile->id();
182
183      if ($instance && ($instance->getProfile()?->id() !== $profile_id)) {
184        $instance->setProfile($profile_id);
185      }
186      $instance->save();
187    }
188
189    // Do also overrides.
190    if ($profile = $this->getDisplayBuilderOverrideProfile()) {
191      $profile_id = (string) $profile->id();
192      $storage = $this->entityTypeManager->getStorage('display_builder_instance');
193
194      foreach ($storage->loadMultiple() as $override) {
195        /** @var \Drupal\display_builder\InstanceInterface $override */
196        if (!$this->isOverrideOfCurrentDisplay($override)) {
197          continue;
198        }
199
200        if ($override->getProfile()->id() === $profile_id) {
201          continue;
202        }
203        $override->setProfile($profile_id);
204        $override->save();
205      }
206    }
207
208    parent::postSave($storage, $update);
209  }
210
211  /**
212   * Deletes the display builder instance if it exists.
213   *
214   * @see \Drupal\Core\Entity\Display\EntityViewDisplayInterface
215   */
216  public function delete(): void {
217    if ($instance = $this->getInstance()) {
218      $instance->delete();
219    }
220    parent::delete();
221  }
222
223  /**
224   * Builds a renderable array for the components of a set of entities.
225   *
226   * @param \Drupal\Core\Entity\FieldableEntityInterface[] $entities
227   *   The entities being displayed.
228   *
229   * @return array
230   *   A renderable array for the entities, indexed by the same keys as the
231   *   $entities array parameter.
232   *
233   * @see \Drupal\Core\Entity\Display\EntityViewDisplayInterface
234   */
235  public function buildMultiple(array $entities): array {
236    $build_list = parent::buildMultiple($entities);
237
238    // If no display builder enabled, stop here and return:
239    // - 'Manage Display' build if this trait is used in EntityViewDisplay
240    // - 'Layout Builder' build if used in LayoutBuilderEntityViewDisplay.
241    if (!$this->isDisplayBuilderEnabled()) {
242      // This is also preventing the availability of Display Builder overrides
243      // when Display Builder is not used for the entity view display.
244      // @todo Is it something we want to keep like that?
245      // @see https://www.drupal.org/project/display_builder/issues/3540048
246      return $build_list;
247    }
248
249    foreach ($entities as $id => $entity) {
250      $sources = [];
251
252      if ($this->isDisplayBuilderOverridable()) {
253        $display_builder_field = $this->getDisplayBuilderOverrideField();
254        $overridden_field = $entity->get($display_builder_field);
255        /** @var \Drupal\display_builder\DisplayBuildableInterface $buildable */
256        $buildable = $this->displayBuildableManager->createInstance('entity_view_override', ['field' => $overridden_field]);
257        $sources = $buildable->getSources();
258      }
259
260      // If the overridden field is empty fallback to the entity view.
261      if (\count($sources) === 0) {
262        $sources = $this->displayBuildable()->getSources();
263      }
264
265      // We clear the display because we only want our renderable.
266      $build_list[$id] = [];
267      // @see entity.html.twig
268      $build_list[$id]['content'] = $this->buildSources($entity, $sources);
269    }
270
271    return $build_list;
272  }
273
274  /**
275   * Check if the instance is overriding this display.
276   *
277   * @param \Drupal\display_builder\InstanceInterface $instance
278   *   A list of display builder instances.
279   *
280   * @return bool
281   *   Is the instance overriding this display?
282   */
283  protected function isOverrideOfCurrentDisplay(InstanceInterface $instance): bool {
284    $parts = EntityViewOverride::checkInstanceId((string) $instance->id());
285
286    if (!$parts) {
287      return FALSE;
288    }
289
290    if ($parts['entity_type_id'] !== $this->getTargetEntityTypeId()) {
291      return FALSE;
292    }
293
294    if ($parts['field_name'] !== $this->getDisplayBuilderOverrideField()) {
295      return FALSE;
296    }
297
298    return TRUE;
299  }
300
301  /**
302   * Gets the available contexts for a given entity.
303   *
304   * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
305   *   The entity.
306   *
307   * @return \Drupal\Core\Plugin\Context\ContextInterface[]
308   *   An array of context objects for a given entity.
309   */
310  protected function getContextsForEntity(FieldableEntityInterface $entity): array {
311    $available_context_ids = \array_keys($this->contextRepository()->getAvailableContexts());
312
313    return [
314      'view_mode' => new Context(ContextDefinition::create('string'), $this->getMode()),
315      'entity' => EntityContext::fromEntity($entity),
316      'display' => EntityContext::fromEntity($this),
317    ] + $this->contextRepository()->getRuntimeContexts($available_context_ids);
318  }
319
320  /**
321   * Wraps the context repository service.
322   *
323   * @return \Drupal\Core\Plugin\Context\ContextRepositoryInterface
324   *   The context repository service.
325   */
326  protected function contextRepository(): ContextRepositoryInterface {
327    return \Drupal::service('context.repository');
328  }
329
330  /**
331   * Gets the Display Builder instance.
332   *
333   * @return \Drupal\display_builder\InstanceInterface|null
334   *   A display builder instance.
335   */
336  protected function getInstance(): ?InstanceInterface {
337    $instance_id = $this->displayBuildable()->getInstanceId();
338    /** @var \Drupal\display_builder\InstanceInterface|null $instance */
339    $instance = $this->entityTypeManager->getStorage('display_builder_instance')->load($instance_id);
340    $this->instance = $instance;
341
342    return $this->instance;
343  }
344
345  /**
346   * Gets the display buildable manager.
347   *
348   * @return \Drupal\display_builder\DisplayBuildableInterface
349   *   The manager for display buildable.
350   */
351  protected function displayBuildable(): DisplayBuildableInterface {
352    /** @var \Drupal\display_builder\DisplayBuildableInterface $buildable */
353    $buildable = $this->displayBuildableManager->createInstance('entity_view', ['entity' => $this]);
354
355    return $buildable;
356  }
357
358  /**
359   * Loads display builder by id.
360   *
361   * @param string $display_builder_id
362   *   The display builder ID.
363   *
364   * @return \Drupal\display_builder\ProfileInterface|null
365   *   The display builder, or NULL if not found.
366   */
367  private function loadDisplayBuilder(string $display_builder_id): ?ProfileInterface {
368    if (empty($display_builder_id)) {
369      return NULL;
370    }
371    $storage = $this->entityTypeManager->getStorage('display_builder_profile');
372
373    /** @var \Drupal\display_builder\ProfileInterface $display_builder */
374    $display_builder = $storage->load($display_builder_id);
375
376    return $display_builder;
377  }
378
379  /**
380   * Builds the render array for the sources of a given entity.
381   *
382   * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
383   *   The entity.
384   * @param array $sources
385   *   The sources to build.
386   *
387   * @return array
388   *   The render array representing the sources of the entity.
389   */
390  private function buildSources(FieldableEntityInterface $entity, array $sources): array {
391    $contexts = $this->getContextsForEntity($entity);
392    $cacheability = new CacheableMetadata();
393    $fake_build = [];
394
395    foreach ($sources as $source_data) {
396      $fake_build = $this->componentElementBuilder->buildSource($fake_build, 'content', [], $source_data, $contexts);
397    }
398    $build = $fake_build['#slots']['content'] ?? [];
399    $build['#cache'] = $fake_build['#cache'] ?? [];
400    // The render array is built based on decisions made by SourceStorage
401    // plugins, and therefore it needs to depend on the accumulated
402    // cacheability of those decisions.
403    $cacheability->applyTo($build);
404
405    return $build;
406  }
407
408}

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.

EntityViewDisplayTrait->buildMultiple
235  public function buildMultiple(array $entities): array {
236    $build_list = parent::buildMultiple($entities);
237
238    // If no display builder enabled, stop here and return:
239    // - 'Manage Display' build if this trait is used in EntityViewDisplay
240    // - 'Layout Builder' build if used in LayoutBuilderEntityViewDisplay.
241    if (!$this->isDisplayBuilderEnabled()) {
246      return $build_list;
249    foreach ($entities as $id => $entity) {
249    foreach ($entities as $id => $entity) {
249    foreach ($entities as $id => $entity) {
250      $sources = [];
251
252      if ($this->isDisplayBuilderOverridable()) {
253        $display_builder_field = $this->getDisplayBuilderOverrideField();
254        $overridden_field = $entity->get($display_builder_field);
255        /** @var \Drupal\display_builder\DisplayBuildableInterface $buildable */
256        $buildable = $this->displayBuildableManager->createInstance('entity_view_override', ['field' => $overridden_field]);
257        $sources = $buildable->getSources();
258      }
259
260      // If the overridden field is empty fallback to the entity view.
261      if (\count($sources) === 0) {
261      if (\count($sources) === 0) {
262        $sources = $this->displayBuildable()->getSources();
263      }
264
265      // We clear the display because we only want our renderable.
266      $build_list[$id] = [];
249    foreach ($entities as $id => $entity) {
250      $sources = [];
251
252      if ($this->isDisplayBuilderOverridable()) {
253        $display_builder_field = $this->getDisplayBuilderOverrideField();
254        $overridden_field = $entity->get($display_builder_field);
255        /** @var \Drupal\display_builder\DisplayBuildableInterface $buildable */
256        $buildable = $this->displayBuildableManager->createInstance('entity_view_override', ['field' => $overridden_field]);
257        $sources = $buildable->getSources();
258      }
259
260      // If the overridden field is empty fallback to the entity view.
261      if (\count($sources) === 0) {
262        $sources = $this->displayBuildable()->getSources();
263      }
264
265      // We clear the display because we only want our renderable.
266      $build_list[$id] = [];
249    foreach ($entities as $id => $entity) {
250      $sources = [];
251
252      if ($this->isDisplayBuilderOverridable()) {
253        $display_builder_field = $this->getDisplayBuilderOverrideField();
254        $overridden_field = $entity->get($display_builder_field);
255        /** @var \Drupal\display_builder\DisplayBuildableInterface $buildable */
256        $buildable = $this->displayBuildableManager->createInstance('entity_view_override', ['field' => $overridden_field]);
257        $sources = $buildable->getSources();
258      }
259
260      // If the overridden field is empty fallback to the entity view.
261      if (\count($sources) === 0) {
262        $sources = $this->displayBuildable()->getSources();
263      }
264
265      // We clear the display because we only want our renderable.
266      $build_list[$id] = [];
267      // @see entity.html.twig
268      $build_list[$id]['content'] = $this->buildSources($entity, $sources);
269    }
270
271    return $build_list;
272  }
EntityViewDisplayTrait->buildSources
390  private function buildSources(FieldableEntityInterface $entity, array $sources): array {
391    $contexts = $this->getContextsForEntity($entity);
392    $cacheability = new CacheableMetadata();
393    $fake_build = [];
394
395    foreach ($sources as $source_data) {
395    foreach ($sources as $source_data) {
395    foreach ($sources as $source_data) {
396      $fake_build = $this->componentElementBuilder->buildSource($fake_build, 'content', [], $source_data, $contexts);
395    foreach ($sources as $source_data) {
396      $fake_build = $this->componentElementBuilder->buildSource($fake_build, 'content', [], $source_data, $contexts);
397    }
398    $build = $fake_build['#slots']['content'] ?? [];
399    $build['#cache'] = $fake_build['#cache'] ?? [];
400    // The render array is built based on decisions made by SourceStorage
401    // plugins, and therefore it needs to depend on the accumulated
402    // cacheability of those decisions.
403    $cacheability->applyTo($build);
404
405    return $build;
406  }
EntityViewDisplayTrait->calculateDependencies
33    parent::calculateDependencies();
34
35    if (!$this->displayBuildable()->getInstanceId()) {
37      return $this;
41    $instance = $this->entityTypeManager->getStorage('display_builder_instance')->load($this->displayBuildable()->getInstanceId());
42
43    if (!$instance) {
44      return $this;
46    $contexts = $instance->getContexts();
47
48    if (!$contexts) {
49      return $this;
52    foreach ($this->displayBuildable()->getSources() as $source_data) {
52    foreach ($this->displayBuildable()->getSources() as $source_data) {
52    foreach ($this->displayBuildable()->getSources() as $source_data) {
53      /** @var \Drupal\ui_patterns\SourceInterface $source */
54      $source = $this->sourcePluginManager->getSource('', [], $source_data, $contexts);
52    foreach ($this->displayBuildable()->getSources() as $source_data) {
53      /** @var \Drupal\ui_patterns\SourceInterface $source */
54      $source = $this->sourcePluginManager->getSource('', [], $source_data, $contexts);
55      $this->addDependencies($source->calculateDependencies());
56    }
57
58    return $this;
59  }
EntityViewDisplayTrait->contextRepository
327    return \Drupal::service('context.repository');
328  }
EntityViewDisplayTrait->delete
217    if ($instance = $this->getInstance()) {
218      $instance->delete();
219    }
220    parent::delete();
220    parent::delete();
221  }
EntityViewDisplayTrait->displayBuildable
353    $buildable = $this->displayBuildableManager->createInstance('entity_view', ['entity' => $this]);
354
355    return $buildable;
356  }
EntityViewDisplayTrait->getContextsForEntity
310  protected function getContextsForEntity(FieldableEntityInterface $entity): array {
311    $available_context_ids = \array_keys($this->contextRepository()->getAvailableContexts());
312
313    return [
314      'view_mode' => new Context(ContextDefinition::create('string'), $this->getMode()),
315      'entity' => EntityContext::fromEntity($entity),
316      'display' => EntityContext::fromEntity($this),
317    ] + $this->contextRepository()->getRuntimeContexts($available_context_ids);
318  }
EntityViewDisplayTrait->getDisplayBuilderOverrideField
131    return $this->getThirdPartySetting('display_builder', DisplayBuildableInterface::OVERRIDE_FIELD_PROPERTY);
132  }
EntityViewDisplayTrait->getDisplayBuilderOverrideProfile
143    $display_builder_id = $this->getThirdPartySetting('display_builder', DisplayBuildableInterface::OVERRIDE_PROFILE_PROPERTY);
144
145    if ($display_builder_id === NULL) {
146      return NULL;
149    return $this->loadDisplayBuilder($display_builder_id);
150  }
EntityViewDisplayTrait->getInstance
337    $instance_id = $this->displayBuildable()->getInstanceId();
338    /** @var \Drupal\display_builder\InstanceInterface|null $instance */
339    $instance = $this->entityTypeManager->getStorage('display_builder_instance')->load($instance_id);
340    $this->instance = $instance;
341
342    return $this->instance;
343  }
EntityViewDisplayTrait->isDisplayBuilderEnabled
72    if ($this->getOriginalMode() === static::CUSTOM_MODE) {
73      return FALSE;
76    return (bool) $this->displayBuildable()->getProfile();
77  }
EntityViewDisplayTrait->isDisplayBuilderOverridable
161    return !empty($this->getDisplayBuilderOverrideField())
162      && $this->getDisplayBuilderOverrideProfile() !== NULL;
162      && $this->getDisplayBuilderOverrideProfile() !== NULL;
163  }
EntityViewDisplayTrait->isOverrideOfCurrentDisplay
283  protected function isOverrideOfCurrentDisplay(InstanceInterface $instance): bool {
284    $parts = EntityViewOverride::checkInstanceId((string) $instance->id());
285
286    if (!$parts) {
287      return FALSE;
290    if ($parts['entity_type_id'] !== $this->getTargetEntityTypeId()) {
291      return FALSE;
294    if ($parts['field_name'] !== $this->getDisplayBuilderOverrideField()) {
295      return FALSE;
298    return TRUE;
299  }
EntityViewDisplayTrait->loadDisplayBuilder
367  private function loadDisplayBuilder(string $display_builder_id): ?ProfileInterface {
368    if (empty($display_builder_id)) {
369      return NULL;
371    $storage = $this->entityTypeManager->getStorage('display_builder_profile');
372
373    /** @var \Drupal\display_builder\ProfileInterface $display_builder */
374    $display_builder = $storage->load($display_builder_id);
375
376    return $display_builder;
377  }
EntityViewDisplayTrait->onDependencyRemoval
90  public function onDependencyRemoval(array $dependencies): bool {
91    $changed = parent::onDependencyRemoval($dependencies);
92
93    // Loop through all sources and determine if the removed dependencies are
94    // used by their plugins.
95    /** @var \Drupal\display_builder\InstanceInterface $instance */
96    $instance = $this->getInstance();
97
98    // @todo not working when content entity type is deleted.
99    if (!$instance) {
100      return TRUE;
103    $contexts = $instance->getContexts();
104
105    foreach ($this->displayBuildable()->getSources() as $source_data) {
105    foreach ($this->displayBuildable()->getSources() as $source_data) {
107      $source = $this->sourcePluginManager->getSource('', [], $source_data, $contexts);
108      $source_dependencies = $source->calculateDependencies();
109      $source_removed_dependencies = $this->getPluginRemovedDependencies($source_dependencies, $dependencies);
110
111      if ($source_removed_dependencies) {
105    foreach ($this->displayBuildable()->getSources() as $source_data) {
106      /** @var \Drupal\ui_patterns\SourceInterface $source */
107      $source = $this->sourcePluginManager->getSource('', [], $source_data, $contexts);
108      $source_dependencies = $source->calculateDependencies();
109      $source_removed_dependencies = $this->getPluginRemovedDependencies($source_dependencies, $dependencies);
110
111      if ($source_removed_dependencies) {
112        // @todo Allow the plugins to react to their dependency removal in
113        // https://www.drupal.org/project/drupal/issues/2579743.
114        // $this->removeSource($delta);
115        $changed = TRUE;
105    foreach ($this->displayBuildable()->getSources() as $source_data) {
105    foreach ($this->displayBuildable()->getSources() as $source_data) {
106      /** @var \Drupal\ui_patterns\SourceInterface $source */
107      $source = $this->sourcePluginManager->getSource('', [], $source_data, $contexts);
108      $source_dependencies = $source->calculateDependencies();
109      $source_removed_dependencies = $this->getPluginRemovedDependencies($source_dependencies, $dependencies);
110
111      if ($source_removed_dependencies) {
112        // @todo Allow the plugins to react to their dependency removal in
113        // https://www.drupal.org/project/drupal/issues/2579743.
114        // $this->removeSource($delta);
115        $changed = TRUE;
116      }
117    }
118
119    return $changed;
120  }
EntityViewDisplayTrait->postSave
175  public function postSave(EntityStorageInterface $storage, $update = TRUE): void {
176    if ($profile = $this->displayBuildable()->getProfile()) {
177      $this->displayBuildable()->initInstanceIfMissing();
178
179      // Save the profile in the instance if changed.
180      $instance = $this->getInstance();
181      $profile_id = (string) $profile->id();
182
183      if ($instance && ($instance->getProfile()?->id() !== $profile_id)) {
183      if ($instance && ($instance->getProfile()?->id() !== $profile_id)) {
183      if ($instance && ($instance->getProfile()?->id() !== $profile_id)) {
184        $instance->setProfile($profile_id);
185      }
186      $instance->save();
186      $instance->save();
187    }
188
189    // Do also overrides.
190    if ($profile = $this->getDisplayBuilderOverrideProfile()) {
190    if ($profile = $this->getDisplayBuilderOverrideProfile()) {
191      $profile_id = (string) $profile->id();
192      $storage = $this->entityTypeManager->getStorage('display_builder_instance');
193
194      foreach ($storage->loadMultiple() as $override) {
194      foreach ($storage->loadMultiple() as $override) {
196        if (!$this->isOverrideOfCurrentDisplay($override)) {
197          continue;
200        if ($override->getProfile()->id() === $profile_id) {
201          continue;
194      foreach ($storage->loadMultiple() as $override) {
195        /** @var \Drupal\display_builder\InstanceInterface $override */
196        if (!$this->isOverrideOfCurrentDisplay($override)) {
197          continue;
198        }
199
200        if ($override->getProfile()->id() === $profile_id) {
201          continue;
202        }
203        $override->setProfile($profile_id);
194      foreach ($storage->loadMultiple() as $override) {
195        /** @var \Drupal\display_builder\InstanceInterface $override */
196        if (!$this->isOverrideOfCurrentDisplay($override)) {
197          continue;
198        }
199
200        if ($override->getProfile()->id() === $profile_id) {
201          continue;
202        }
203        $override->setProfile($profile_id);
204        $override->save();
205      }
206    }
207
208    parent::postSave($storage, $update);
208    parent::postSave($storage, $update);
209  }