Commit bf4a3b40 authored by Volodymyr Mostepaniuk's avatar Volodymyr Mostepaniuk
Browse files

Issue #3295753 by mostepaniukvm: Introduce custom elements display form.

parent 8cd2300f
Loading
Loading
Loading
Loading
+13 −4
Original line number Diff line number Diff line
core.entity_view_display.*.*.*.third_party.ce:
core.entity_view_display.*.*.*.third_party_settings.custom_elements_ui:
  type: mapping
  label: 'Per-view-mode Custom elements settings'
  mapping:
    enabled:
      type: boolean
      label: 'Whether the Custom Elements Display builder is enabled for this display'
    custom_element_name:
      type: string
      label: 'Custom element name'
    custom_element_fields:
      type: sequence
      sequence:
@@ -14,15 +17,21 @@ custom_elements_ui.field:
  type: mapping
  label: 'CE field'
  mapping:
    field_name:
      type: string
      label: 'Field Name'
    label:
      type: string
      label: 'CE name'
    is_slot:
      type: bool
      label: 'is Slot'
    type:
      type: string
      label: 'Widget type machine name'
    weight:
      type: integer
      label: 'Weight'
    region:
      type: string
      label: 'Region'
    ce_formatter:
      type: string
      label: 'CE Formatter'
+9 −18
Original line number Diff line number Diff line
@@ -5,11 +5,9 @@
 * Provides hook implementations for Custom Elements UI.
 */

use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\custom_elements_ui\Form\DefaultsEntityForm;
use Drupal\custom_elements_ui\Form\OverridesEntityForm;
use Drupal\custom_elements_ui\Form\EntityCustomElementsDisplayForm;
use Drupal\field_ui\FieldUI;

/**
@@ -18,25 +16,18 @@ use Drupal\field_ui\FieldUI;
function custom_elements_ui_entity_type_alter(array &$entity_types) {
  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
  $entity_types['entity_view_display']
    ->setFormClass('custom_elements_builder', DefaultsEntityForm::class);

  // Ensure every fieldable entity type has a custom_elements form.
  foreach ($entity_types as $entity_type) {
    if ($entity_type->entityClassImplements(FieldableEntityInterface::class)) {
      $entity_type->setFormClass('custom_elements_builder', OverridesEntityForm::class);
    }
  }
    ->setFormClass('custom_elements_builder', EntityCustomElementsDisplayForm::class);
}

/**
* Implements hook_form_FORM_ID_alter() for \Drupal\field_ui\Form\EntityFormDisplayEditForm.
* Implements hook_form_FORM_ID_alter() for \Drupal\field_ui\Form\EntityViewDisplayEditForm.
*/
function custom_elements_ui_form_entity_view_display_edit_form_alter(&$form, FormStateInterface $form_state) {
  /** @var \Drupal\Core\Entity\EntityFormInterface $display_form */
  $display_form = $form_state->getFormObject();
  /** @var \Drupal\Core\Entity\Entity\EntityViewDisplay $display_entity */
  $display_entity = $display_form->getEntity();
  $is_enabled = $display_entity->getThirdPartySetting('ce', 'enabled');
  $is_enabled = $display_entity->getThirdPartySetting('custom_elements_ui', 'enabled') ?? FALSE;

  // Hide the table of fields same as in field_ui.
  if ($is_enabled) {
@@ -62,16 +53,16 @@ function custom_elements_ui_form_entity_view_display_edit_form_alter(&$form, For
    '#access' => $is_enabled,
  ];

  $form['ce'] = [
  $form['custom_elements_ui'] = [
    '#type' => 'details',
    '#open' => TRUE,
    '#title' => t('Custom Elements'),
    '#tree' => TRUE,
  ];

  $form['ce']['enabled'] = [
  $form['custom_elements_ui']['enabled'] = [
    '#type' => 'checkbox',
    '#title' => t('Use Custom Elements Builder'),
    '#title' => t('Use Custom Elements Display'),
    '#default_value' => $is_enabled,
  ];

@@ -84,11 +75,11 @@ function custom_elements_ui_form_entity_view_display_edit_form_alter(&$form, For
 * @see custom_elements_ui_form_entity_view_display_edit_form_alter()
 */
function _custom_elements_ui_entity_view_display_edit_form_submit($form, FormStateInterface $form_state) {
  $set_enabled = (bool) $form_state->getValue(['ce', 'enabled'], FALSE);
  $set_enabled = (bool) $form_state->getValue(['custom_elements_ui', 'enabled'], FALSE);
  /** @var \Drupal\Core\Entity\EntityFormInterface $display_form */
  $display_form = $form_state->getFormObject();
  /** @var \Drupal\Core\Entity\Entity\EntityViewDisplay $display_entity */
  $display_entity = $display_form->getEntity();
  $display_entity->setThirdPartySetting('ce', 'enabled', $set_enabled);
  $display_entity->setThirdPartySetting('custom_elements_ui', 'enabled', $set_enabled);
  $display_entity->save();
}
+0 −68
Original line number Diff line number Diff line
<?php

namespace Drupal\custom_elements_ui\Form;

use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\layout_builder\SectionStorageInterface;

/**
 * Provides a form containing the Layout Builder UI for defaults.
 *
 * @internal
 *   Form classes are internal.
 */
class DefaultsEntityForm extends EntityForm {

  /**
   * {@inheritdoc}
   */
  public function getBaseFormId() {
    return $this->getEntity()->getEntityTypeId() . '_ce_builder_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL) {
    $form['ce'] = [
      '#type' => 'markup',
      '#markup' => 'Coming soon...',
    ];
    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function buildEntity(array $form, FormStateInterface $form_state) {
    $entity = parent::buildEntity($form, $form_state);
    return $entity;
  }

  /**
   * {@inheritdoc}
   */
  public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) {
    $route_parameters = $route_match->getParameters()->all();

    return $this->entityTypeManager->getStorage('entity_view_display')->load($route_parameters['entity_type_id'] . '.' . $route_parameters['bundle'] . '.' . $route_parameters['view_mode_name']);
  }

  /**
   * {@inheritdoc}
   */
  protected function actions(array $form, FormStateInterface $form_state) {
    $actions = parent::actions($form, $form_state);
    return $actions;
  }

  /**
   * {@inheritdoc}
   */
  public function save(array $form, FormStateInterface $form_state) {
    return parent::save($form, $form_state);
  }

}
+285 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\custom_elements_ui\Form;

use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\PluginSettingsInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\field_ui\FieldUI;
use Drupal\field_ui\Form\EntityDisplayFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a form containing the Custom elements display UI for defaults.
 *
 * @internal
 *   Form classes are internal.
 */
class EntityCustomElementsDisplayForm extends EntityDisplayFormBase {

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('plugin.manager.field.field_type'),
      $container->get('plugin.manager.field.formatter'),
      $container->get('entity_display.repository'),
      $container->get('entity_field.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getBaseFormId() {
    return $this->getEntity()->getEntityTypeId() . '_ce_builder_form';
  }

  /**
   * {@inheritdoc}
   */
  protected function buildFieldRow(FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state) {
    $field_row = parent::buildFieldRow($field_definition, $form, $form_state);
    $field_name = $field_definition->getName();
    $display_component_options = $this->entity->getComponent($field_name);
    $display_options = $this->entity->getThirdPartySetting('custom_elements_ui', 'custom_element_fields');
    $display_options = $display_options[$field_name] ?? [];

    // Override default values.
    $field_row['weight']['#default_value'] = $display_options['weight'] ?? 0;
    $field_row['region']['#default_value'] = $display_options['region'] ?? $display_component_options['region'] ?? 'hidden';
    $field_row['type']['#default_value'] = $display_options['type'] ?? 'hidden';

    // Insert the label column.
    $label = [
      'label' => [
        '#type' => 'textfield',
        '#title' => $this->t('CE name'),
        '#title_display' => 'invisible',
        '#default_value' => $display_options['label'] ?? '',
        '#placeholder' => str_replace('_', '-', substr($field_name, 6)),
        '#size' => 20,
        '#required' => $field_row['region']['#default_value'] !== 'hidden',
      ],
    ];

    $is_slot = [
      'is_slot' => [
        '#type' => 'checkbox',
        '#title' => $this->t('Is Slot'),
        '#title_display' => 'invisible',
        '#default_value' => $display_options['is_slot'] ?? FALSE,
      ],
    ];

    // Insert additional fields.
    $label_position = array_search('plugin', array_keys($field_row));
    $field_row = array_slice($field_row, 0, $label_position, TRUE) + $label + array_slice($field_row, $label_position, count($field_row) - 1, TRUE);
    $field_row = array_slice($field_row, 0, $label_position + 1, TRUE) + $is_slot + array_slice($field_row, $label_position, count($field_row) - 1, TRUE);

    // Update the (invisible) title of the 'plugin' column.
    $field_row['plugin']['#title'] = $this->t('CE Formatter for @title', ['@title' => $field_definition->getLabel()]);
    // @todo Activate when implemented.
    $field_row['plugin']['#disabled'] = TRUE;
    $field_row["settings_edit"]['#access'] = FALSE;

    // @todo Needed?
    if (!empty($field_row['plugin']['settings_edit_form']) && ($plugin = $this->entity->getRenderer($field_name))) {
      $plugin_type_info = $plugin->getPluginDefinition();
      $field_row['plugin']['settings_edit_form']['label']['#markup'] = $this->t('Format settings:') . ' <span class="plugin-name">' . $plugin_type_info['label'] . '</span>';
    }

    return $field_row;
  }

  /**
   * {@inheritdoc}
   */
  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
    $form_values = $form_state->getValues();
    $is_enabled = $entity->getThirdPartySetting('custom_elements_ui', 'enabled');

    // Delete fields if form was submitted but ce display wasn't activated.
    if (!$is_enabled) {
      $entity->setThirdPartySetting('custom_elements_ui', 'custom_element_fields', []);
      parent::copyFormValuesToEntity($entity, $form, $form_state);
    }
    $ce_fields = $entity->getThirdPartySetting('custom_elements_ui', 'custom_element_fields') ?? [];

    if ($this->entity instanceof EntityWithPluginCollectionInterface) {
      // Do not manually update values represented by plugin collections.
      $form_values = array_diff_key($form_values, $this->entity->getPluginCollections());
    }

    // Collect data for 'regular' fields.
    foreach ($form['#fields'] as $field_name) {
      $values = $form_values['fields'][$field_name];
      if ($values['region'] == 'hidden') {
        unset($ce_fields[$field_name]);
      }
      else {
        $options = $ce_fields[$field_name] ?? [];

        // Update field settings only if the submit handler told us to.
        if ($form_state->get('plugin_settings_update') === $field_name) {
          // Only store settings actually used by the selected plugin.
          $default_settings = $this->pluginManager->getDefaultSettings($options['type']);
          $options['settings'] = isset($values['settings_edit_form']['settings']) ? array_intersect_key($values['settings_edit_form']['settings'], $default_settings) : [];
          $options['third_party_settings'] = $values['settings_edit_form']['third_party_settings'] ?? [];
          $form_state->set('plugin_settings_update', NULL);
        }

        $options['type'] = $values['type'];
        $options['weight'] = $values['weight'];
        $options['region'] = $values['region'];
        // Only formatters have configurable label visibility.
        if (isset($values['label'])) {
          $options['label'] = $values['label'];
        }
        $options['is_slot'] = $values['is_slot'];
        $ce_fields[$field_name] = $options;
      }
    }
    $entity->setThirdPartySetting('custom_elements_ui', 'custom_element_fields', $ce_fields);
    $entity->setThirdPartySetting('custom_elements_ui', 'custom_element_name', $form_values['ce_name']);
  }

  /**
   * {@inheritdoc}
   */
  protected function getTableHeader() {
    return [
      $this->t('Field'),
      $this->t('Weight'),
      $this->t('Parent'),
      $this->t('Region'),
      $this->t('CE name'),
      $this->t('Is Slot'),
      ['data' => $this->t('CE Format(coming...)'), 'colspan' => 3],
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['ce_name'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Element name'),
      '#default_value' => $this->entity->getThirdPartySetting('custom_elements_ui', 'custom_element_name') ?? '',
      '#size' => 20,
      '#required' => TRUE,
    ];
    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) {
    $route_parameters = $route_match->getParameters()->all();
    $bundle = $route_parameters['entity_type_id'];
    if (!empty($route_parameters['bundle_key']) && !empty($route_parameters[$route_parameters['bundle_key']])) {
      $bundle_entity = $route_parameters[$route_parameters['bundle_key']];
      if ($bundle_entity instanceof ConfigEntityBundleBase) {
        $bundle = $bundle_entity->id();
      }
    }
    elseif (!empty($route_parameters['bundle'])) {
      $bundle = $route_parameters['bundle'];
    }

    return $this->entityTypeManager->getStorage('entity_view_display')->load($route_parameters['entity_type_id'] . '.' . $bundle . '.' . $route_parameters['view_mode_name']);
  }

  /**
   * {@inheritdoc}
   */
  protected function getEntityDisplay($entity_type_id, $bundle, $mode) {
    return $this->entityDisplayRepository->getViewDisplay($entity_type_id, $bundle, $mode);
  }

  /**
   * {@inheritdoc}
   */
  protected function getDefaultPlugin($field_type) {
    // @todo Implement with ce formatters.
    return NULL;
  }

  /**
   * {@inheritdoc}
   */
  protected function getDisplayModes() {
    return $this->entityDisplayRepository->getViewModes($this->entity->getTargetEntityTypeId());
  }

  /**
   * {@inheritdoc}
   */
  protected function getDisplayModeOptions() {
    return $this->entityDisplayRepository->getViewModeOptions($this->entity->getTargetEntityTypeId());
  }

  /**
   * {@inheritdoc}
   */
  protected function getDisplayModesLink() {
    return [
      '#type' => 'link',
      '#title' => $this->t('Manage view modes'),
      '#url' => Url::fromRoute('entity.entity_view_mode.collection'),
    ];
  }

  /**
   * {@inheritdoc}
   */
  protected function getOverviewUrl($mode) {
    $entity_type = $this->entityTypeManager->getDefinition($this->entity->getTargetEntityTypeId());
    return Url::fromRoute('entity.entity_view_display.' . $this->entity->getTargetEntityTypeId() . '.view_mode', [
        'view_mode_name' => $mode,
      ] + FieldUI::getRouteBundleParameter($entity_type, $this->entity->getTargetBundle()));
  }

  /**
   * {@inheritdoc}
   */
  protected function thirdPartySettingsForm(PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition, array $form, FormStateInterface $form_state) {
    $settings_form = [];
    // Invoke hook_field_formatter_third_party_settings_form(), keying resulting
    // subforms by module name.
    $this->moduleHandler->invokeAllWith(
      'field_formatter_third_party_settings_form',
      function (callable $hook, string $module) use (&$settings_form, &$plugin, &$field_definition, &$form, &$form_state) {
        $settings_form[$module] = $hook(
          $plugin,
          $field_definition,
          $this->entity->getMode(),
          $form,
          $form_state,
        );
      }
    );
    return $settings_form;
  }

  /**
   * {@inheritdoc}
   */
  protected function alterSettingsSummary(array &$summary, PluginSettingsInterface $plugin, FieldDefinitionInterface $field_definition) {
    $context = [
      'formatter' => $plugin,
      'field_definition' => $field_definition,
      'view_mode' => $this->entity->getMode(),
    ];
    $this->moduleHandler->alter('field_formatter_settings_summary', $summary, $context);
  }

}
+0 −61
Original line number Diff line number Diff line
<?php

namespace Drupal\custom_elements_ui\Form;

use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\layout_builder\SectionStorageInterface;

/**
 * Provides a form containing the Layout Builder UI for overrides.
 *
 * @internal
 *   Form classes are internal.
 */
class OverridesEntityForm extends ContentEntityForm {

  /**
   * {@inheritdoc}
   */
  public function getBaseFormId() {
    return $this->getEntity()->getEntityTypeId() . '_ce_builder_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL) {
    $form['ce'] = [
      '#type' => 'markup',
      '#markup' => 'Coming soon...',
    ];
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function getEntityFromRouteMatch(RouteMatchInterface $route_match, $entity_type_id) {
    $route_parameters = $route_match->getParameters()->all();

    return $this->entityTypeManager->getStorage('entity_view_display')->load($route_parameters['entity_type_id'] . '.' . $route_parameters['bundle'] . '.' . $route_parameters['view_mode_name']);
  }

  /**
   * {@inheritdoc}
   */
  public function save(array $form, FormStateInterface $form_state) {
    $return = parent::save($form, $form_state);
    return $return;
  }

  /**
   * {@inheritdoc}
   */
  protected function actions(array $form, FormStateInterface $form_state) {
    $actions = parent::actions($form, $form_state);
    return $actions;
  }

}
Loading