web-dev-qa-db-fra.com

Comment modifier facilement la définition de champ de base d'une entité par bundle

Nous utilisons le module group dans Drupal 8, qui introduit une entité personnalisée "group". Cette entité comporte un champ de base "label" avec le titre "Title" En tant qu'administrateur de groupes, vous pouvez créer plusieurs types de groupes différents, qui sont traités comme des ensembles pouvant être mis en champ de l'entité de groupe et héritent de son champ de base d'étiquettes.

Selon le type de groupe, nous souhaitons remplacer le titre d'étiquette générique dans les formulaires, les vues, les modèles, etc., par exemple 'Libellé', 'Nom', 'Branche', 'Département', 'Section', ...

Cependant, l'entité de groupe n'expose pas le titre de l'étiquette dans sa forme de configuration comme le fait le module de noeud. Nous avons donc essayé de remplacer le titre en utilisant hook_entity_base_field_info_alter () comme ceci:

/**
 * 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'));
  }
}

Ce qui fonctionne, mais change le titre de tous les bundles.

Notre prochain essai était hook_entity_bundle_field_info_alter () . Il expose les informations sur les ensembles, mais il ne permet pas de modifier les champs de base. Essayer de rajouter la définition de champ de base avec un titre différent (afin de permettre au noyau de fusionner les définitions de champ et de remplacer les définitions de champ de base) a provoqué différentes exceptions d'exécution.

Nous avons donc fini par modifier manuellement les tableaux de génération de formulaires et les titres de widgets, ce qui peut causer des problèmes plus tard lorsque la quantité de types de groupes augmente.

Comment pouvons-nous modifier le titre du champ de base sur une base par paquet sans avoir à étendre le module de groupe ou à modifier manuellement toutes les occurrences des étiquettes de champ de nos entités de groupe?

5
Mario Steinitz

Les étiquettes spécifiques aux bundles pour les champs de base sont stockées dans label d'une entité de configuration BaseFieldOverride :

Définit l'entité de remplacement du champ de base.

Permet de remplacer les champs de base au niveau du bundle.

Annotation du plugin

@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",
  }
)

Lorsque vous obtenez un champ de base de EntityFieldManager :: getFieldDefinitions ($ entity_type_id, $ bundle) , définissez un nouveau libellé pour le champ et enregistrez la définition du champ, puis ce libellé n'est pas stocké dans le type d'entité ( ce qui ne serait pas possible, car c'est dans le code et le même pour tous les bundles), mais dans le remplacement de champ de base mentionné.

9
4k4

La réponse de @ 4k4 nous a mis sur la bonne voie. Pour notre solution, nous avons principalement essayé de modifier les étiquettes de certains types de groupe de base fournis par programme.

Afin d'aider les autres avec un cas d'utilisation similaire, voici comment nous l'avons fait:

Nous avons implémenté hook_entity_bundle_field_info () dans le module qui a fourni notre groupe d'entités de groupe, puis utilisé BaseFieldOverride pour créer les remplacements de champ:

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;
}

Comme indiqué plus loin par @ 4k4 , le remplacement pourrait également être effectué dans d'autres endroits. Par exemple. dans le formulaire, soumettez les gestionnaires pour remplacer les libellés de titre des groupes créés dans l'interface d'administration.

7
Mario Steinitz

Voici une implémentation de BaseFieldOverride sur un formulaire de bundle (en utilisant ConfigEntityBundleBase comme entité de bundle, comme suggéré par Drupal Console 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
Capi Etheriel