Как легко изменить определение базового поля сущности для каждого пакета


Мы используем модуль group в Drupal 8, который вводит пользовательскую сущность "группа". Эта сущность имеет базовое поле "метка" с заголовком "Заголовок". Как администратор групп, вы можете создать несколько различных типов групп, которые обрабатываются как доступные для заполнения пакеты сущности группы и наследуют ее базовое поле метки.

В зависимости от типа группы мы хотим переопределить общий заголовок метки в формах, представлениях, шаблонах и т. Д., Например, "Метка", "Название", "Филиал", "Отдел", "Секция", ...

Однако сущность группы не предоставляет заголовок метки в своей форме конфигурации, как это делает модуль узла. Поэтому мы попытались переопределить заголовок с помощью hook_entity_base_field_info_alter() следующим образом:

/**
 * Implements hook_entity_base_field_info_alter().
 */
function mymodule_entity_base_field_info_alter(&$fields, \Drupal\Core\Entity\EntityTypeInterface $entity_type) {
  if ($entity_type->id() == 'group' && !empty($fields['label'])) {
    $fields['label']->setLabel(t('Name'));
  }
}

Который работает, но меняет название для всех пакетов.

Наша следующая попытка была hook_entity_bundle_field_info_alter(). Он предоставляет информацию о пакете, но не позволяет изменять базовые поля. Пытаясь повторное добавление определения базового поля с другим заголовком (чтобы позволить ядру объединить определения полей и переопределить определения базовых полей) вызвало различные исключения во время выполнения.

Таким образом, мы закончили тем, что вручную изменили массивы построения форм и заголовки виджетов, что может вызвать проблемы позже, когда количество типов групп увеличится.

Как мы можем изменить заголовок базового поля на основе каждого пакета без необходимости расширять модуль группы или вручную изменять все вхождения меток полей объектов нашей группы?

 5
Author: kenorb, 2018-01-07

3 answers

Конкретные метки пакетов для базовых полей хранятся в label объекта конфигурации basefieldoverride:

Определяет сущность переопределения базового поля.

Позволяет переопределять базовые поля на уровне пакета.

Аннотация плагина

@ConfigEntityType(
  id = "base_field_override",
  label = @Translation("Base field override"),
  handlers = {
    "storage" = "Drupal\Core\Field\BaseFieldOverrideStorage",
    "access" = "Drupal\Core\Field\BaseFieldOverrideAccessControlHandler",
  },
  config_prefix = "base_field_override",
  entity_keys = {
    "id" = "id",
    "label" = "label"
  },
  config_export = {
    "id",
    "field_name",
    "entity_type",
    "bundle",
    "label",
    "description",
    "required",
    "translatable",
    "default_value",
    "default_value_callback",
    "settings",
    "field_type",
  }
)

Когда вы получаете базовое поле из entityfieldmanager::getfielddefinitions($entity_type_id, $bundle), установите новую метку для поля и сохраните определение поля, тогда эта метка будет не хранится в типе сущности (что было бы невозможно, потому что это в коде и одинаково для всех пакетов), но в упомянутом переопределении базового поля.

 9
Author: 4k4, 2018-01-07 12:58:44

Ответ @4k4 вывел нас на правильный путь. Для нашего решения мы в первую очередь попытались изменить метки для некоторых программных типов базовых групп.

Чтобы помочь другим в аналогичном случае использования, вот как мы это сделали:

Мы реализовали hook_entity_bundle_field_info() в модуле, который предоставил наш пакет групповых сущностей, а затем использовал basefieldoverride для создания переопределений полей:

use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\Entity\BaseFieldOverride;

/**
 * Implements hook_entity_bundle_field_info().
 */
function ourgroupmodule_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
  $fields = [];

  // Whether the hook implementation was called for our group type.
  if ($entity_type->id() == 'group' && $bundle == 'ourgroup' && !empty($base_field_definitions['label'])) {
    // Create a base field override with custom title.
    $field = BaseFieldOverride::createFromBaseFieldDefinition($base_field_definitions['label'], $bundle);
    $field->setLabel(t('Our group label title'));
    $fields['label'] = $field;
  }

  return $fields;
}

Как указано далее с помощью @4k4 переопределение может быть выполнено и в других местах. Например, в форме отправить обработчики для переопределения заголовков групп, созданных в пользовательском интерфейсе администратора.

 7
Author: Mario Steinitz, 2018-01-08 01:24:02

Вот реализация BaseFieldOverride в форме пакета (с использованием ConfigEntityBundleBase в качестве объекта пакета, как предложено консолью Drupal generate:entity:content).

class CustomEntityTypeForm extends EntityForm {
  public function form(array $form, FormStateInterface $form_state) {
    $form = parent::form($form, $form_state);
    /* ... */
    $form['target_bundles'] = [
      '#title' => $this->t('Node types this bundle supports.'),
      '#type' => 'checkboxes',
      '#options' => $node_type_options,
      '#default_value' => $this->entity->getTargetBundles() ?: [],
    ];
    return $form;
  }

  public function save(array $form, FormStateInterface $form_state) {
    /*...*/
    $field_manager = \Drupal::service('entity_field.manager');
    $definitions = $field_manager->getFieldDefinitions('attendance', $this->entity->id());

    /* the name of the base field is 'bundles' */
    if ($definitions['bundles'] instanceof BaseFieldOverride) {
      $override = $definitions['bundles'];
    }
    else {
      $override = BaseFieldOverride::createFromBaseFieldDefinition($definitions['bundles'], $this->entity->id());
    }

    /* my actual override just changes handler settings for an entity reference widget */
    $override->setSetting('handler_settings', ['bundles' => $this->entity->get('bundles')]);
    $override->save()

    /* Proceeds to saving the form normally */
  }

}
 1
Author: Capi Etheriel, 2019-07-02 15:10:09