Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x

EntityDisplayModeFormBase.php

Namespace

Drupal\field_ui\Form

File

core/modules/field_ui/src/Form/EntityDisplayModeFormBase.php

View source
<?php

namespace Drupal\field_ui\Form;

use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Drupal\field_ui\FieldUI;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides the generic base class for entity display mode forms.
 */
abstract class EntityDisplayModeFormBase extends EntityForm {
    
    /**
     * The entity type definition.
     *
     * @var \Drupal\Core\Entity\EntityTypeInterface
     */
    protected $entityType;
    
    /**
     * The display context. Either 'view' or 'form'.
     *
     * @var string
     */
    protected string $displayContext;
    
    /**
     * The entity type for which the display mode is being created or edited.
     *
     * @var string|null
     */
    protected ?string $targetEntityTypeId;
    
    /**
     * {@inheritdoc}
     */
    protected function init(FormStateInterface $form_state) {
        parent::init($form_state);
        $this->entityType = $this->entityTypeManager
            ->getDefinition($this->entity
            ->getEntityTypeId());
        $this->displayContext = str_replace([
            'entity_',
            '_mode',
        ], '', $this->entityType
            ->id());
    }
    
    /**
     * Constructs a EntityDisplayModeFormBase object.
     *
     * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entityTypeBundleInfo
     *   The entity type bundle service.
     * @param \Drupal\Core\Entity\EntityDisplayRepository $entityDisplayRepository
     *   The entity display repository.
     */
    public function __construct(EntityTypeBundleInfoInterface $entityTypeBundleInfo, EntityDisplayRepositoryInterface $entityDisplayRepository) {
    }
    
    /**
     * {@inheritdoc}
     */
    public static function create(ContainerInterface $container) {
        return new static($container->get('entity_type.bundle.info'), $container->get('entity_display.repository'));
    }
    
    /**
     * {@inheritdoc}
     */
    public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL) {
        if (!$entity_type_id && !$this->entity
            ->isNew()) {
            $entity_type_id = $this->entity
                ->getTargetType();
        }
        $this->targetEntityTypeId = $entity_type_id;
        return parent::buildForm($form, $form_state);
    }
    
    /**
     * {@inheritdoc}
     */
    public function form(array $form, FormStateInterface $form_state) {
        $form['label'] = [
            '#type' => 'textfield',
            '#title' => $this->t('Name'),
            '#maxlength' => 100,
            '#default_value' => $this->entity
                ->label(),
            '#required' => TRUE,
        ];
        $form['description'] = [
            '#title' => $this->t('Description'),
            '#type' => 'textarea',
            '#default_value' => $this->entity
                ->getDescription(),
            '#description' => $this->t('This text will be displayed on the @mode_label list page.', [
                '@mode_label' => $this->entity
                    ->getEntityType()
                    ->getPluralLabel(),
            ]),
        ];
        $form['id'] = [
            '#type' => 'machine_name',
            '#description' => $this->t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'),
            '#disabled' => !$this->entity
                ->isNew(),
            '#default_value' => $this->entity
                ->id(),
            '#field_prefix' => $this->entity
                ->isNew() ? $this->entity
                ->getTargetType() . '.' : '',
            '#machine_name' => [
                'exists' => [
                    $this,
                    'exists',
                ],
                'replace_pattern' => '[^a-z0-9_.]+',
            ],
        ];
        $bundle_info_service = $this->entityTypeBundleInfo;
        $bundles = $bundle_info_service->getAllBundleInfo();
        $definition = $this->entityTypeManager
            ->getDefinition($this->entity
            ->isNew() ? $this->targetEntityTypeId : $this->entity
            ->getTargetType());
        $bundles_by_entity = [];
        $defaults = [];
        foreach (array_keys($bundles[$definition->id()]) as $bundle) {
            $bundles_by_entity[$bundle] = $bundles[$definition->id()][$bundle]['label'];
            // Determine default display modes.
            if (!$this->entity
                ->isNew()) {
                [
                    ,
                    $display_mode_name,
                ] = explode('.', $this->entity
                    ->id());
                if ($this->getDisplayByContext($bundle, $display_mode_name)) {
                    $defaults[$bundle] = $bundle;
                }
            }
        }
        $form['bundles_by_entity'] = [
            '#type' => 'checkboxes',
            '#title' => $this->t('Enable this @display-mode for the following @bundle-label types:', [
                '@display-mode' => $this->entityType
                    ->getSingularLabel(),
                '@bundle-label' => $definition->getLabel(),
            ]),
            '#description' => $this->t('This @display-mode will still be available for the rest of the @bundle-label types if not checked here, but it will not be enabled by default.', [
                '@bundle-label' => $definition->getLabel(),
                '@display-mode' => $this->entityType
                    ->getSingularLabel(),
            ]),
            '#options' => $bundles_by_entity,
            '#default_value' => $defaults,
        ];
        return $form;
    }
    
    /**
     * Determines if the display mode already exists.
     *
     * @param string|int $entity_id
     *   The entity ID.
     * @param array $element
     *   The form element.
     *
     * @return bool
     *   TRUE if the display mode exists, FALSE otherwise.
     */
    public function exists($entity_id, array $element) {
        // Do not allow to add internal 'default' view mode.
        if ($entity_id == 'default') {
            return TRUE;
        }
        
        /** @var \Drupal\Core\Config\Entity\ConfigEntityStorageInterface $storage */
        $storage = $this->entityTypeManager
            ->getStorage($this->entity
            ->getEntityTypeId());
        return (bool) $storage->getQuery()
            ->condition('id', $element['#field_prefix'] . $entity_id)
            ->execute();
    }
    
    /**
     * {@inheritdoc}
     */
    public function save(array $form, FormStateInterface $form_state) {
        $this->messenger()
            ->addStatus($this->t('Saved the %label @entity-type.', [
            '%label' => $this->entity
                ->label(),
            '@entity-type' => $this->entityType
                ->getSingularLabel(),
        ]));
        $this->entity
            ->save();
        \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
        $form_state->setRedirectUrl($this->entity
            ->toUrl('collection'));
        [
            ,
            $display_mode_name,
        ] = explode('.', $form_state->getValue('id'));
        $target_entity_id = $this->targetEntityTypeId;
        foreach ($form_state->getValue('bundles_by_entity') as $bundle => $value) {
            if (!empty($value)) {
                // Add a new entity view/form display if it doesn't already exist.
                if (!$this->getDisplayByContext($bundle, $display_mode_name)) {
                    $display = $this->getEntityDisplay($target_entity_id, $bundle, 'default')
                        ->createCopy($display_mode_name);
                    $display->save();
                }
                // This message is still helpful, even if the view/form display hasn't
                // changed, so we keep it outside the above check.
                $url = $this->getOverviewUrl($display_mode_name, $value);
                $bundle_info_service = $this->entityTypeBundleInfo;
                $bundles = $bundle_info_service->getAllBundleInfo();
                $bundle_label = $bundles[$target_entity_id][$bundle]['label'];
                $display_mode_label = $form_state->getValue('label');
                $this->messenger()
                    ->addStatus($this->t('<a href=":url">Configure the %display_mode_label %mode mode for %bundle_label</a>.', [
                    '%mode' => $this->displayContext,
                    '%display_mode_label' => $display_mode_label,
                    '%bundle_label' => $bundle_label,
                    ':url' => $url->toString(),
                ]));
            }
            else {
                // The view/form display has been unchecked, so we need to delete this.
                // There's no confirmation of deleting the view/form display on the node
                // content type forms either, so we match that behavior.
                if ($display = $this->getDisplayByContext($bundle, $display_mode_name)) {
                    $display->delete();
                }
            }
        }
    }
    
    /**
     * Returns an entity display object to be used by this form.
     *
     * @param string $entity_type_id
     *   The target entity type ID of the entity display.
     * @param string $bundle
     *   The target bundle of the entity display.
     * @param string $mode
     *   A view or form mode.
     *
     * @return \Drupal\Core\Entity\Display\EntityDisplayInterface
     *   An entity display.
     */
    private function getEntityDisplay($entity_type_id, $bundle, $mode) {
        return match ($this->displayContext) {    'view' => $this->entityDisplayRepository
                ->getViewDisplay($entity_type_id, $bundle, $mode),
            'form' => $this->entityDisplayRepository
                ->getFormDisplay($entity_type_id, $bundle, $mode),
        
        };
    }
    
    /**
     * Returns the Url object for a specific entity (form) display edit form.
     *
     * @param string $mode
     *   The form or view mode.
     * @param string $bundle
     *   The entity bundle name.
     *
     * @return \Drupal\Core\Url
     *   A Url object for the overview route.
     */
    private function getOverviewUrl($mode, $bundle) : Url {
        $entity_type = $this->entityTypeManager
            ->getDefinition($this->targetEntityTypeId);
        return match ($this->displayContext) {    'view' => Url::fromRoute('entity.entity_view_display.' . $this->targetEntityTypeId . '.view_mode', [
                'view_mode_name' => $mode,
            ] + FieldUI::getRouteBundleParameter($entity_type, $bundle)),
            'form' => Url::fromRoute('entity.entity_form_display.' . $this->targetEntityTypeId . '.form_mode', [
                'form_mode_name' => $mode,
            ] + FieldUI::getRouteBundleParameter($entity_type, $bundle)),
        
        };
    }
    
    /**
     * Load the view display for a given bundle and view mode name.
     *
     * @param string $bundle
     *   The entity bundle to load the view display for.
     * @param string $view_mode_name
     *   The view mode name such as "full_content" to load the view display for.
     *
     * @return \Drupal\Core\Entity\Display\EntityViewDisplayInterface|null
     *   Returns the view display, or NULL if one does not exist.
     */
    private function getViewDisplay(string $bundle, string $view_mode_name) : ?EntityViewDisplayInterface {
        $view_mode_id = $this->targetEntityTypeId . '.' . $bundle . '.' . $view_mode_name;
        return $this->entityTypeManager
            ->getStorage('entity_view_display')
            ->load($view_mode_id);
    }
    
    /**
     * Load the form display for a given bundle and form mode name.
     *
     * @param string $bundle
     *   The entity bundle to load the form display for.
     * @param string $form_mode_name
     *   The form mode name to load the form display for.
     *
     * @return \Drupal\Core\Entity\Display\EntityFormDisplayInterface|null
     *   Returns the form display, or NULL if one does not exist.
     */
    private function getFormDisplay(string $bundle, string $form_mode_name) : ?EntityFormDisplayInterface {
        $form_mode_id = $this->targetEntityTypeId . '.' . $bundle . '.' . $form_mode_name;
        return $this->entityTypeManager
            ->getStorage('entity_form_display')
            ->load($form_mode_id);
    }
    
    /**
     * Returns View or Form display based on display context.
     *
     * @param string $bundle
     *   The entity bundle to load the display for.
     * @param string $display_mode_name
     *   The display mode name to load the display for.
     *
     * @return \Drupal\Core\Entity\Display\EntityFormDisplayInterface|\Drupal\Core\Entity\Display\EntityViewDisplayInterface|null
     *   Returns the display, or NULL if one does not exist.
     */
    private function getDisplayByContext(string $bundle, string $display_mode_name) : EntityFormDisplayInterface|EntityViewDisplayInterface|null {
        return match ($this->displayContext) {    'view' => $this->getViewDisplay($bundle, $display_mode_name),
            'form' => $this->getFormDisplay($bundle, $display_mode_name),
        
        };
    }

}

Classes

Title Deprecated Summary
EntityDisplayModeFormBase Provides the generic base class for entity display mode forms.

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal