diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml index 7e39e0c..b89bc26 100644 --- a/core/config/schema/core.entity.schema.yml +++ b/core/config/schema/core.entity.schema.yml @@ -364,7 +364,7 @@ field.formatter.settings.entity_reference_label: field.formatter.settings.entity_reference_field: type: mapping - label: 'Entity reference referenced entity field formatter display format settings' + label: 'Rendered field from referenced entity settings' mapping: field_name: label: 'Machine name of the field' diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceFieldFormatter.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceFieldFormatter.php index 6138d10..0937d01 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceFieldFormatter.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldFormatter/EntityReferenceFieldFormatter.php @@ -58,6 +58,13 @@ class EntityReferenceFieldFormatter extends EntityReferenceFormatterBase impleme protected $entityTypeBundleInfo; /** + * The list of supported fields, prepared as options (machine_name => label). + * + * @var array + */ + protected $availableFieldOptions; + + /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { @@ -129,16 +136,19 @@ public function viewElements(FieldItemListInterface $items, $langcode) { /** @var \Drupal\Core\Entity\FieldableEntityInterface $entity */ $entities = $this->getEntitiesToView($items, $langcode); + $field_name = $this->getFieldName()['machine_name']; + $formatter_type = $this->getFormatterType($field_name)['machine_name']; + $formatter_settings = [ + 'type' => $formatter_type, + 'settings' => $this->getSetting('settings'), + 'label' => $this->getSetting('label'), + ]; + $build = []; foreach ($entities as $delta => $entity) { - $field_name = $this->getFieldName()['machine_name']; - $formatter_type = $this->getFormatterType($field_name)['machine_name']; - $formatter_settings = [ - 'type' => $formatter_type, - 'settings' => $this->getSetting('settings'), - 'label' => $this->getSetting('label'), - ]; - $build[$delta] = $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId())->viewField($entity->get($field_name), array_filter($formatter_settings)); + if ($entity->hasField($field_name)) { + $build[$delta] = $this->entityTypeManager->getViewBuilder($entity->getEntityTypeId())->viewField($entity->get($field_name), array_filter($formatter_settings)); + } } return $build; } @@ -150,7 +160,11 @@ public function viewElements(FieldItemListInterface $items, $langcode) { * An associative array of supported fields, where keys are machine names * and values are human-readable field labels. */ - protected function getAvailableFieldNames() { + protected function getAvailableFieldOptions() { + if ($this->availableFieldOptions) { + return $this->availableFieldOptions; + } + $entity_type_id = $this->fieldDefinition->getSetting('target_type'); $entity_type = $this->entityTypeManager->getDefinition($entity_type_id); // We always show the entity label as an option to be selected. @@ -166,17 +180,18 @@ protected function getAvailableFieldNames() { } $target_bundles = empty($this->fieldDefinition->getSetting('handler_settings')['target_bundles']) ? array_keys($this->entityTypeBundleInfo->getBundleInfo($entity_type_id)) : $this->fieldDefinition->getSetting('handler_settings')['target_bundles']; - foreach ($target_bundles as $value) { - $bundle_field_names = array_map( - function (FieldDefinitionInterface $field_definition) { - if ($field_definition->isDisplayConfigurable('view')) { - return $field_definition->getLabel(); - } - }, - $this->entityFieldManager->getFieldDefinitions($entity_type_id, $value) - ); - $field_names = array_merge($field_names, array_filter($bundle_field_names)); + foreach ($target_bundles as $bundle) { + $bundle_field_names = []; + /** @var \Drupal\Core\Field\FieldDefinitionInterface $field_definition */ + foreach ($this->entityFieldManager->getFieldDefinitions($entity_type_id, $bundle) as $field_machine_name => $field_definition) { + if ($field_definition->isDisplayConfigurable('view')) { + $bundle_field_names[$field_machine_name] = $field_definition->getLabel(); + } + } + $field_names = array_merge($field_names, $bundle_field_names); } + + $this->availableFieldOptions = $field_names; return $field_names; } @@ -208,20 +223,20 @@ protected function getAvailableFormatterOptions(FieldStorageDefinitionInterface * Ajax callback for field name change. */ public static function onFieldNameChange(array $form, FormStateInterface $form_state) { - return $form['fields'][$form_state->getStorage()['plugin_settings_edit']]['plugin']['settings_edit_form']['settings']; + return $form['fields'][$form_state->get('plugin_settings_edit')]['plugin']['settings_edit_form']['settings']; } /** * Ajax callback for formatter type change. */ public static function onFormatterTypeChange(array $form, FormStateInterface $form_state) { - return $form['fields'][$form_state->getStorage()['plugin_settings_edit']]['plugin']['settings_edit_form']['settings']['settings']; + return $form['fields'][$form_state->get('plugin_settings_edit')]['plugin']['settings_edit_form']['settings']['settings']; } /** * Rebuilds the form on select submit. */ - public static function rebuildSubmit(array $form, FormStateInterface $form_state) { + public static function rebuildSubmit(array &$form, FormStateInterface $form_state) { $form_state->setRebuild(TRUE); } @@ -231,10 +246,10 @@ public static function rebuildSubmit(array $form, FormStateInterface $form_state public function settingsForm(array $form, FormStateInterface $form_state) { $form = parent::settingsForm($form, $form_state); $target_entity_type_id = $this->fieldDefinition->getSetting('target_type'); - $field_name_options = $this->getAvailableFieldNames(); + $field_name_options = $this->getAvailableFieldOptions(); $field_storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($target_entity_type_id); // Field on the target entity this formatter is currently displaying. - $selected_field_name = $this->getSettingFromFormState($form_state, 'field_name'); + $selected_field_name = $this->getSetting('field_name', $form_state); if (!$selected_field_name) { // The first field is used as default in case of no value set. $selected_field_name = array_keys($field_name_options)[0]; @@ -262,13 +277,13 @@ public function settingsForm(array $form, FormStateInterface $form_state) { '#type' => 'select', '#title' => $this->t('Label'), '#options' => EntityViewDisplayEditForm::getFieldLabelOptions(), - '#default_value' => $this->getSettingFromFormState($form_state, 'label'), + '#default_value' => $this->getSetting('label', $form_state), ]; - if ($selected_field_name && !empty($field_storage)) { + if ($selected_field_name) { $formatter_options = $this->getAvailableFormatterOptions($field_storage); - $formatter_type = $this->getSettingFromFormState($form_state, 'type'); - $settings = $this->getSettingFromFormState($form_state, 'settings'); + $formatter_type = $this->getSetting('type', $form_state); + $settings = $this->getSetting('settings', $form_state); if (!isset($formatter_options[$formatter_type])) { $formatter_type = array_keys($formatter_options)[0]; $settings = []; @@ -341,20 +356,37 @@ public function settingsSummary() { /** * Wrapper around ::getSetting() to carry over values from the form state. * + * @param string $key + * The setting name. * @param \Drupal\Core\Form\FormStateInterface $form_state * The form state. - * @param string $setting - * The setting name. * * @return mixed|null * The value of the setting, or NULL if absent. */ - protected function getSettingFromFormState(FormStateInterface $form_state, $setting) { + public function getSetting($key, FormStateInterface $form_state = NULL) { + if (!$form_state) { + return parent::getSetting($key); + } + $field_name = $this->fieldDefinition->getName(); - if ($form_state->hasValue(['fields', $field_name, 'settings_edit_form', 'settings', $setting])) { - return $form_state->getValue(['fields', $field_name, 'settings_edit_form', 'settings', $setting]); + if ($form_state->hasValue([ + 'fields', + $field_name, + 'settings_edit_form', + 'settings', + $key, + ])) { + return $form_state->getValue([ + 'fields', + $field_name, + 'settings_edit_form', + 'settings', + $key, + ]); } - return $this->getSetting($setting); + + return parent::getSetting($key); } /** @@ -367,15 +399,15 @@ protected function getSettingFromFormState(FormStateInterface $form_state, $sett * If no field was configured yet, will try to return the first field * available on the target entity. * - * @see \Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceReferencedEntityFieldFormatter::getAvailableFieldNames() + * @see \Drupal\Core\Field\Plugin\Field\FieldFormatter\EntityReferenceReferencedEntityFieldFormatter::getAvailableFieldOptions() */ protected function getFieldName() { - $field_name_options = $this->getAvailableFieldNames(); + $field_name_options = $this->getAvailableFieldOptions(); if (!$field_name = $this->getSetting('field_name')) { $field_name = array_keys($field_name_options)[0]; } $field['machine_name'] = $field_name; - $field['label'] = !empty($field_name_options[$field_name]) ? $field_name_options[$field_name] : NULL; + $field['label'] = $field_name_options[$field_name]; return $field; }