Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 134
n/a
0 / 0
n/a
0 / 0
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
EntityViewDisplayFormTrait
0.00% covered (danger)
0.00%
0 / 134
n/a
0 / 0
n/a
0 / 0
0.00% covered (danger)
0.00%
0 / 8
870
0.00% covered (danger)
0.00%
0 / 1
 submitForm
0.00% covered (danger)
0.00%
0 / 16
n/a
0 / 0
n/a
0 / 0
0.00% covered (danger)
0.00%
0 / 1
20
 entityViewDisplayForm
0.00% covered (danger)
0.00%
0 / 26
n/a
0 / 0
n/a
0 / 0
0.00% covered (danger)
0.00%
0 / 1
20
 buildOverridesForm
0.00% covered (danger)
0.00%
0 / 55
n/a
0 / 0
n/a
0 / 0
0.00% covered (danger)
0.00%
0 / 1
12
 getAlreadyMappedFields
0.00% covered (danger)
0.00%
0 / 11
n/a
0 / 0
n/a
0 / 0
0.00% covered (danger)
0.00%
0 / 1
30
 getSourceFieldAsOptions
0.00% covered (danger)
0.00%
0 / 14
n/a
0 / 0
n/a
0 / 0
0.00% covered (danger)
0.00%
0 / 1
42
 buildExtraFieldRow
0.00% covered (danger)
0.00%
0 / 3
n/a
0 / 0
n/a
0 / 0
0.00% covered (danger)
0.00%
0 / 1
6
 buildFieldRow
0.00% covered (danger)
0.00%
0 / 3
n/a
0 / 0
n/a
0 / 0
0.00% covered (danger)
0.00%
0 / 1
6
 copyFormValuesToEntity
0.00% covered (danger)
0.00%
0 / 6
n/a
0 / 0
n/a
0 / 0
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\display_builder_entity_view\Form;
6
7use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
8use Drupal\Core\Entity\EntityInterface;
9use Drupal\Core\Field\FieldDefinitionInterface;
10use Drupal\Core\Form\FormStateInterface;
11use Drupal\Core\Url;
12use Drupal\display_builder\ConfigFormBuilderInterface;
13use Drupal\display_builder_entity_view\Entity\DisplayBuilderEntityDisplayInterface;
14use Drupal\display_builder_entity_view\Entity\DisplayBuilderOverridableInterface;
15
16/**
17 * Common methods for entity view display form.
18 */
19trait EntityViewDisplayFormTrait {
20
21  /**
22   * Form submission handler.
23   *
24   * @param array $form
25   *   An associative array containing the structure of the form.
26   * @param \Drupal\Core\Form\FormStateInterface $form_state
27   *   The current state of the form.
28   */
29  public function submitForm(array &$form, FormStateInterface $form_state): void {
30    parent::submitForm($form, $form_state);
31
32    // @todo we should have always a fallback.
33    $display_builder_config = $form_state->getValue([ConfigFormBuilderInterface::PROFILE_PROPERTY]) ?? 'default';
34
35    // Empty means disabled.
36    if (empty($display_builder_config)) {
37      $this->entity->unsetThirdPartySetting('display_builder', ConfigFormBuilderInterface::PROFILE_PROPERTY);
38    }
39    else {
40      $this->entity->setThirdPartySetting('display_builder', ConfigFormBuilderInterface::PROFILE_PROPERTY, $display_builder_config);
41    }
42
43    $display_builder_override = $form_state->getValue([ConfigFormBuilderInterface::OVERRIDE_FIELD_PROPERTY]) ?? '';
44
45    // Empty means disabled.
46    if (empty($display_builder_override)) {
47      $this->entity->unsetThirdPartySetting('display_builder', ConfigFormBuilderInterface::OVERRIDE_FIELD_PROPERTY);
48    }
49    else {
50      $this->entity->setThirdPartySetting('display_builder', ConfigFormBuilderInterface::OVERRIDE_FIELD_PROPERTY, $display_builder_override);
51    }
52
53    $display_builder_override_profile = $form_state->getValue([ConfigFormBuilderInterface::OVERRIDE_PROFILE_PROPERTY]) ?? '';
54
55    // Empty means disabled.
56    if (empty($display_builder_override_profile)) {
57      $this->entity->unsetThirdPartySetting('display_builder', ConfigFormBuilderInterface::OVERRIDE_PROFILE_PROPERTY);
58    }
59    else {
60      $this->entity->setThirdPartySetting('display_builder', ConfigFormBuilderInterface::OVERRIDE_PROFILE_PROPERTY, $display_builder_override_profile);
61    }
62
63    $this->entity->save();
64    $this->localTaskManager->clearCachedDefinitions();
65    $this->routeBuilder->rebuild();
66  }
67
68  /**
69   * Provides form elements to enable Display Builder.
70   *
71   * @param array $form
72   *   The form structure.
73   *
74   * @return array
75   *   The modified form.
76   */
77  protected function entityViewDisplayForm(array $form): array {
78    $is_display_builder_enabled = $this->entity->isDisplayBuilderEnabled();
79
80    if ($is_display_builder_enabled) {
81      // Hide the table of fields.
82      $form['fields']['#access'] = FALSE;
83      $form['#fields'] = [];
84      $form['#extra'] = [];
85    }
86
87    $form['manage_display_builder'] = [
88      '#type' => 'link',
89      '#title' => $this->t('Display builder'),
90      '#weight' => -11,
91      '#attributes' => ['class' => ['button']],
92      '#url' => $this->entity->getBuilderUrl(),
93      '#access' => $is_display_builder_enabled,
94    ];
95
96    if (isset($form['modes'])) {
97      $form['modes']['#weight'] = 0;
98    }
99
100    $form['display_builder_wrapper'] = [
101      '#type' => 'details',
102      '#open' => TRUE,
103      '#title' => $this->t('Display builder'),
104      '#weight' => 1,
105    ];
106
107    $form['display_builder_wrapper'][ConfigFormBuilderInterface::PROFILE_PROPERTY] = $this->configFormBuilder->build($this->entity, FALSE);
108
109    /** @var \Drupal\display_builder_entity_view\Entity\DisplayBuilderEntityDisplayInterface $entity */
110    $entity = $this->getEntity();
111
112    if ($entity instanceof DisplayBuilderOverridableInterface) {
113      $form['display_builder_wrapper'][ConfigFormBuilderInterface::PROFILE_PROPERTY]['override_form'] = $this->buildOverridesForm($entity);
114    }
115
116    return $form;
117  }
118
119  /**
120   * Build the form for entity display overrides per content.
121   *
122   * @param \Drupal\display_builder_entity_view\Entity\DisplayBuilderEntityDisplayInterface $entity
123   *   The entity.
124   *
125   * @return array
126   *   The renderable form array.
127   */
128  protected function buildOverridesForm(DisplayBuilderEntityDisplayInterface|DisplayBuilderOverridableInterface $entity): array {
129    $entity_type_id = $entity->getTargetEntityTypeId();
130    $options = $this->getSourceFieldAsOptions();
131    $target_entity_type_id = $this->entityTypeManager->getDefinition($entity_type_id)->getBundleEntityType();
132    $description = [
133      '#title' => $this->t('Add a UI Patterns Source field'),
134      '#type' => 'link',
135      '#attributes' => [
136        'data-dialog-type' => 'modal',
137        'data-dialog-options' => \json_encode([
138          'title' => 'Add field: Source (UI Patterns)',
139          'width' => '800',
140        ]),
141        'class' => ['use-ajax'],
142      ],
143      '#url' => Url::fromRoute("field_ui.field_storage_config_add_sub_{$entity_type_id}", [
144        $target_entity_type_id => $entity->getTargetBundle(),
145        'display_as_group' => 'Group',
146        'selected_field_type' => 'ui_patterns_source',
147      ]),
148      '#suffix' => '.',
149    ];
150
151    if (empty($options)) {
152      $description = [
153        [
154          '#plain_text' => $this->t('No eligible field found.') . ' ',
155        ],
156        $description,
157      ];
158    }
159    /** @var \Drupal\display_builder_entity_view\Entity\DisplayBuilderOverridableInterface $overridable */
160    $overridable = $entity;
161    $form = [];
162    $form[ConfigFormBuilderInterface::OVERRIDE_FIELD_PROPERTY] = [
163      '#type' => 'select',
164      '#title' => $this->t('Select a field to override this display per content'),
165      '#options' => $options,
166      '#empty_option' => $this->t('- Disabled -'),
167      '#default_value' => $overridable->getDisplayBuilderOverrideField(),
168      '#description' => $description,
169    ];
170
171    $form[ConfigFormBuilderInterface::OVERRIDE_PROFILE_PROPERTY] = [
172      '#type' => 'select',
173      '#title' => $this->t('Override profile'),
174      '#description' => $this->t('The profile used for content overrides.'),
175      '#options' => $this->configFormBuilder->getAllowedProfiles(),
176      '#default_value' => $overridable->getDisplayBuilderOverrideProfile()?->id(),
177      '#states' => [
178        'invisible' => [
179          ':input[name="' . ConfigFormBuilderInterface::OVERRIDE_FIELD_PROPERTY . '"]' => ['filled' => FALSE],
180        ],
181      ],
182    ];
183
184    if (!$this->configFormBuilder->isAllowed($entity)) {
185      $form[ConfigFormBuilderInterface::OVERRIDE_FIELD_PROPERTY]['#disabled'] = TRUE;
186      unset($form[ConfigFormBuilderInterface::OVERRIDE_FIELD_PROPERTY]['#description']);
187      $form[ConfigFormBuilderInterface::OVERRIDE_PROFILE_PROPERTY]['#disabled'] = TRUE;
188    }
189
190    return $form;
191  }
192
193  /**
194   * Returns an array of UI Patterns Source fields which are already mapped.
195   *
196   * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $current_display
197   *   The current display.
198   *
199   * @return array
200   *   An array of field names that are already mapped to the current display.
201   */
202  protected function getAlreadyMappedFields(EntityViewDisplayInterface $current_display): array {
203    /** @var \Drupal\display_builder_entity_view\Entity\DisplayBuilderEntityDisplayInterface[] $displays */
204    $displays = $this->entityTypeManager->getStorage('entity_view_display')->loadByProperties([
205      'targetEntityType' => $current_display->getTargetEntityTypeId(),
206      'bundle' => $current_display->getTargetBundle(),
207    ]);
208    $field_names = [];
209
210    foreach ($displays as $display) {
211      if ($display instanceof DisplayBuilderOverridableInterface) {
212        if ($display->isDisplayBuilderOverridable()
213          && $current_display->id() !== $display->id()) {
214          $field_names[] = $display->getDisplayBuilderOverrideField();
215        }
216      }
217    }
218
219    return $field_names;
220  }
221
222  /**
223   * Returns UI Patterns source fields as options.
224   *
225   * @return array
226   *   An associative array of field names and labels.
227   */
228  protected function getSourceFieldAsOptions(): array {
229    /** @var \Drupal\display_builder_entity_view\Entity\DisplayBuilderEntityDisplayInterface $display */
230    $display = $this->getEntity();
231    $field_definitions = $this->entityFieldManager->getFieldDefinitions(
232      $display->getTargetEntityTypeId(),
233      $display->getTargetBundle(),
234    );
235    $fields = [];
236
237    if ($display instanceof DisplayBuilderOverridableInterface
238      && $display instanceof EntityViewDisplayInterface
239    ) {
240      $already_mapped = $this->getAlreadyMappedFields($display);
241
242      foreach ($field_definitions as $field_name => $field_definition) {
243        if ($field_definition->getType() === 'ui_patterns_source'
244          && !\in_array($field_name, $already_mapped, TRUE)
245        ) {
246          $fields[$field_name] = $field_definition->getLabel();
247        }
248      }
249    }
250
251    return $fields;
252  }
253
254  /**
255   * Builds the table row structure for a single extra field.
256   *
257   * @param string $field_id
258   *   The field ID.
259   * @param array $extra_field
260   *   The pseudo-field element.
261   *
262   * @return array
263   *   A table row array.
264   */
265  protected function buildExtraFieldRow($field_id, $extra_field): array {
266    if ($this->entity->isDisplayBuilderEnabled()) {
267      return [];
268    }
269
270    return parent::buildExtraFieldRow($field_id, $extra_field);
271  }
272
273  /**
274   * Builds the table row structure for a single field.
275   *
276   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
277   *   The field definition.
278   * @param array $form
279   *   An associative array containing the structure of the form.
280   * @param \Drupal\Core\Form\FormStateInterface $form_state
281   *   The current state of the form.
282   *
283   * @return array
284   *   A table row array.
285   */
286  protected function buildFieldRow(FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state): array {
287    if ($this->entity->isDisplayBuilderEnabled()) {
288      return [];
289    }
290
291    return parent::buildFieldRow($field_definition, $form, $form_state);
292  }
293
294  /**
295   * Copies top-level form values to entity properties.
296   *
297   * This should not change existing entity properties that are not being edited
298   * by this form.
299   *
300   * @param \Drupal\Core\Entity\EntityInterface $entity
301   *   The entity the current form should operate upon.
302   * @param array $form
303   *   A nested array of form elements comprising the form.
304   * @param \Drupal\Core\Form\FormStateInterface $form_state
305   *   The current state of the form.
306   *
307   * @see \Drupal\Core\Form\ConfigFormBase::copyFormValuesToConfig()
308   */
309  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state): void {
310    /** @var \Drupal\display_builder_entity_view\Entity\DisplayBuilderEntityDisplayInterface $entity */
311    // Do not process field values if Display Builder is or will be enabled.
312    $set_enabled = (bool) $form_state->getValue(['display_builder', 'enabled'], FALSE);
313    $already_enabled = $entity->isDisplayBuilderEnabled();
314
315    if ($already_enabled || $set_enabled) {
316      $form['#fields'] = [];
317      $form['#extra'] = [];
318    }
319
320    parent::copyFormValuesToEntity($entity, $form, $form_state);
321  }
322
323}

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.