You are here

public function DisplayCloner::cloneDisplay in Field tools 8

Clone or merge a form or view display to a new bundle.

Display settings are copied to the new bundle.

  • Fields which are present on the source but not the target are ignored.

If the target already has this display:

  • Fields which are on the both source and target have their settings overwritten.
  • Fields which are on the target only but not the source have their settings left untouched.

Parameters

\Drupal\Core\Entity\EntityDisplayBase $source_entity_display: The entity display (form or view) to clone.

string $destination_bundle: The destination bundle.

File

src/DisplayCloner.php, line 72

Class

DisplayCloner
Contains methods for cloning displays.

Namespace

Drupal\field_tools

Code

public function cloneDisplay(EntityDisplayBase $source_entity_display, $destination_bundle) {
  $display_entity_type = $source_entity_display
    ->getEntityTypeId();

  // Have to deduce the context from the entity type, as there's no accessor
  // for $displayContext: see https://www.drupal.org/node/2823807.
  if ($display_entity_type == 'entity_form_display') {
    $context = 'form';
  }
  else {
    $context = 'view';
  }
  $target_entity_type_id = $source_entity_display
    ->getTargetEntityTypeId();
  $source_bundle = $source_entity_display
    ->getTargetBundle();
  $mode_name = $source_entity_display
    ->getMode();

  // Try to load the destination display.
  $destination_display = $this->entityTypeManager
    ->getStorage($display_entity_type)
    ->load($target_entity_type_id . '.' . $destination_bundle . '.' . $mode_name);
  if (empty($destination_display)) {

    // Create a new display, duplicating the source. We keep the mode the same
    // but then change the target bundle.
    $destination_display = $source_entity_display
      ->createCopy($source_entity_display
      ->getMode());
    $destination_display
      ->setTargetBundle($destination_bundle);
  }

  // Get all fields on destination bundle.
  $destination_bundle_fields = array_filter($this->entityFieldManager
    ->getFieldDefinitions($target_entity_type_id, $destination_bundle), function ($field_definition) {
    return !$field_definition
      ->isComputed();
  });

  // Get the display components from the source display, and copy them to the
  // destination.
  // This only returns visible fields.
  $components = $source_entity_display
    ->getComponents();
  foreach ($components as $field_name => $source_display_field_component) {

    // Skip fields that do not exist on the destination bundle.
    if (!isset($destination_bundle_fields[$field_name])) {
      continue;
    }
    $destination_display
      ->setComponent($field_name, $source_display_field_component);
  }

  // Copy field groups.
  if ($this->moduleHandler
    ->moduleExists('field_group')) {
    $field_group_settings = $source_entity_display
      ->getThirdPartySettings('field_group');
    foreach ($field_group_settings as $group_id => $group_settings) {

      // Remove any fields in groups which do not exist on the destination
      // bundle.
      foreach ($group_settings['children'] as $index => $child_field) {
        if (!isset($destination_bundle_field_names[$child_field])) {
          unset($group_settings['children'][$index]);
        }
      }

      // Skip groups which don't have any fields left in them.
      if (empty($group_settings['children'])) {
        continue;
      }

      // TODO: rekey the numeric 'children' array?
      // Set the group in the destination display.
      // (There's no setThirdPartySetting*s*() method...)
      $destination_display
        ->setThirdPartySetting('field_group', $group_id, $group_settings);
    }
  }

  // Save the display.
  $destination_display
    ->save();
}