Drupal 8 - ConfigEntityBase

ConfigEntityBase, les entités pour la configuration

Le précédent article de la série sur la Création d'un module avec Drupal 8 a introduit la réflexion sur la manière de mettre en place la configuration globale de notre module. Nous allons maintenant voir comment implémenter cette logique pour arriver à nos fins.

ConfigEntityBase

Je vous l'avais expliqué lorsque nous avons survolé la génération d'un type d'entité avec Drupal Console, il y a deux grands types d'entité dans Drupal 8. Le premier type est défini via la classe ContentEntityBase, et elle permet de créer des entités dont les données seront sauvegardées dans des tables spécifiques de la base de données. Le second type d'entité est défini via la classe ConfigEntityBase, et permet de créer des entités dont les données seront sauvegardées dans la table "config". Ce type d'entité est dédié à la sauvegarde de données de configuration.

En général, les données de configuration pour un élément ne concernent que quelques lignes dans la base de données. Au contraire, les données entités (par exemple node:article) peuvent se compter par centaines, milliers ou plus dans la base de données. C'est pour cette raison qu'il est important de bien choisir le type d'entité de base à utiliser lors de la mise en place. Rien n'empèche de stocker de la configuration dans des tables dédiées en utilisant ContentEntityBase. Le contraire, stocker des contenus dans la table "config" peut par contre s'avérer néfaste.

Dans le cadre de notre module Internal Link, la configuration globale, celle qui va permettre de rattacher des informations de configuration à des types d'entité, va pouvoir aisément être stockées dans la table "config", nous utiliserons donc une classe héritant de ConfigEntityBase comme type d'entité permettant le stockage.

Génération de l'entité

Je vois que vous avez déjà ouvert votre terminal, vous avez compris qu'une fois n'est pas coutume, Drupal Console va reprendre du service. Heu, comment vous dire... Ok... Nous pouvons utiliser Drupal Console, mais cette fois-ci, la génération sera bien trop conséquente par rapport à nos besoins. En fait, lorsque j'ai implémenté cette entité, je me suis beaucoup référé à des modules du noyau, je n'ai pas du tout utilisé Drupal Console. Ce dernier va générer toute une série de fichiers type Interface, ListBuilder, HtmlRouteProvider, il va aller modifier des fichiers YAML, mais nous n'avons pas besoin de tout ça...

Bon, qu'à celà ne tienne, essayons:

MacPro:drupal8 titouille$ drupal generate:entity:config
 Enter the module name [internal_link]:
 > 
 
 Enter the class of your new config entity [DefaultEntity]:
 > InternalLinkSettings
 
 Enter the name of your new config entity [internal_link_settings]:
 > 
 
 Enter the label of your new config entity [Internal link settings]:
 > 
 
 Enter the base-path for the config entity routes [/admin/structure]:
 > admin/config/search/internal_link/il_settings 
 
Generated or updated files
 Site path: /Users/titouille/Dev/web/htdocs/sabugo/drupal8
 1 - modules/custom/internal_link/config/schema/internal_link_settings.schema.yml
 2 - modules/custom/internal_link/internal_link.links.menu.yml
 3 - modules/custom/internal_link/internal_link.links.action.yml
 4 - modules/custom/internal_link/src/InternalLinkSettingsInterface.php
 5 - modules/custom/internal_link/src/Entity/InternalLinkSettings.php
 6 - modules/custom/internal_link/src/InternalLinkSettingsHtmlRouteProvider.php
 7 - modules/custom/internal_link/src/Form/InternalLinkSettingsForm.php
 8 - modules/custom/internal_link/src/Form/InternalLinkSettingsDeleteForm.php
 9 - modules/custom/internal_link/src/InternalLinkSettingsListBuilder.php
MacPro:drupal8 titouille$ 

Nous voyons la liste des fichiers générés. Et là, c'est déjà problématique. La génération a écrasé le fichier /src/Form/InternalLinkSettingsForm.php qui avait été généré lorsque nous avons créé l'entité InternalLink. Ce fichier est sensé correspondre au formulaire "d'accueil" pour la configuration de notre type d'entité internal_link (admin/config/seach/internal_link/settings) et il vient d'être écrasé par un fichier sensé être le formulaire d'édition de notre nouvelle entité InternalLinkSettings... Nous voyons toute une série d'autres fichiers dont la structure ressemble beaucoup à la génération de notre entité InternalLink... Sauf que notre configuration, nous ne voulons pas la créer "à la main" comme une entité de type contenu. Nous voulons l'associer à un formulaire, qui de surcroit existe (ou plutôt existait) déjà. Il faut revoir ces fichiers et revenir à un état plus acceptable de notre module.

Nous allons donc supprimer ce qui n'est pas nécessaire, et faire un peu de ménage dans les fichiers YAML.

A supprimer:

  • src/InternalLinkSettingsHtmlRouteProvider.php
  • src/InternalLinkSettingsListBuilder.php
  • src/Form/InternalLinkSettingsDeleteForm.php

A modifier:

  • internal_link.links.action.yml: supprimer l'entrée correspondant à entity.internal_link_settings.add_form
  • internal_link.links.menu.yml: supprimer l'entrée correspondant à entity.internal_link_settings.collection

Nous devons remettre en état notre fichier src/Form/InternalSettingsForm.php avec le code suivant:

/**
 * @file
 * Contains \Drupal\internal_link\Form\InternalLinkSettingsForm.
 */
 
namespace Drupal\internal_link\Form;
 
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
 
/**
 * Class InternalLinkSettingsForm.
 *
 * @package Drupal\internal_link\Form
 *
 * @ingroup internal_link
 */
class InternalLinkSettingsForm extends FormBase {
  /**
   * Returns a unique string identifying the form.
   *
   * @return string
   *   The unique string identifying the form.
   */
  public function getFormId() {
    return 'InternalLink_settings';
  }
 
  /**
   * Form submission handler.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // Empty implementation of the abstract submit class.
  }
 
 
  /**
   * Defines the settings form for Internal link entities.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   *
   * @return array
   *   Form definition array.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['InternalLink_settings']['#markup'] = 'Settings form for Internal link entities. Manage field settings here.';
    return $form;
  }
}

Enfin, nous allons revoir l'annotation de notre classe InternalLinkSettings, dans src/Entity/InternalLinkSettings.php, pour qu'elle corresponde au code suivant:

/**
 * Defines the InternalLinkSettings entity.
 * 
 * @ConfigEntityType(
 *  id = "internal_link_settings",
 *  label = @Translation("Internal link settings"),
 *  admin_permission = "administer internal link entities",
 *  config_prefix = "internal_link_settings",
 *  entity_keys = {
 *    "id" = "id"
 *  },
 *  list_cache_tags = { "rendered" }
 * )
 */

L'annotation indiquait des classes pour les gestionnaires (handlers), des liens (links), une clé complexe (entity_keys) mais tout ça est superflu. Nous pouvons même supprimer la variable protégée $label car elle ne sera pas utile. Notez la clé "config_prefix", qui correspond à une clé utilisée dans le schéma YAML que nous verrons un peu plus tard. Au final, voilà ce qui devrait rester:

/**
 * @file
 * Contains \Drupal\internal_link\Entity\InternalLinkSettings.
 */
 
namespace Drupal\internal_link\Entity;
 
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\internal_link\InternalLinkSettingsInterface;
 
 
/**
 * Defines the InternalLinkSettings entity.
 * 
 * @ConfigEntityType(
 *  id = "internal_link_settings",
 *  label = @Translation("Internal link settings"),
 *  admin_permission = "administer internal link entities",
 *  config_prefix = "internal_link_settings",
 *  entity_keys = {
 *    "id" = "id"
 *  },
 *  list_cache_tags = { "rendered" }
 * )
 */
class InternalLinkSettings extends ConfigEntityBase implements InternalLinkSettingsInterface {
  /**
   * The Internal link settings ID.
   *
   * @var string
   */
  protected $id;
 
}

Nous devons également modifier le fichier YAML sur le schéma de notre entité (dans /config/schema/internal_link_settings.schema.yml):

internal_link.internal_link_settings.*.*:
  type: config_entity
  label: 'Internal link settings config'
  mapping:
    id:
      type: string
      label: 'ID'

Je l'avais spécifié plus haut, c'est ici que la clé "config_prefix est utilisée: internal_link.internal_link_settings.*.*.

Nous modifions d'abord la clé de base pour passer de internal_link.internal_link_settings.* à internal_link.internal_link_settings.*.*.

Puis nous supprimons les variables label et uuid de la section mapping.

Maintenant que tout ceci est fait, nous pouvons vider le cache du site:

drupal cr all

Afin que nos modifications soient prises en compte, et nous allons pouvoir commencer à implémenter correctement notre entité.

Besoins de l'entité de configuration

Avant de nous lancer dans le code, nous allons déterminer quels sont les besoins en terme de paramétrage. Nous voulons les choses suivantes:

  • $manual_enabled: Un mode d'action manuel;
  • $automatic_enabled: Un mode d'action automatique;
  • $fields: une liste de champs sur lesquels vont s'appliquer les liens;
  • $wrap_html_tag: La possibilité d'entourer notre balise HTML d'un lien;
  • $disallowed_html_tags: La possibilité d'exclure certaines balises HTML du processus de parsing (par exemple, ne pas transformer en lien un mot qui se trouverait dans une balise H1);
  • $highlight_words: Utiliser un mode de surlignage plutôt que la transformation en lien;
  • $word_boundary: Traiter une chaîne de caractère seulement si elle apparait en tant que mot entier, ou traiter une chaîne même si elle correspond à un sous-chaîne d'un mot (par exemple traiter la chaîne "barque" même si elle apparait dans le mot "embarquer");
  • $links_to_process: Définir le nombre maximum de liens différents à traiter;
  • $maximum_application: Définir le nombre de fois ou un même lien sera traité (nous trouvons le mot "barque" 7 fois dans le texte, mais nous ne traitons que les 2 premières occurrences);

Armé de ces besoins, nous pouvons maintenant implémenter notre entité de manière correcte.

Implémentation de l'entité

Pour notre entité, nous avons besoin d'un identifiant unique. Ce dernier se basera sur la combinaison de deux valeurs: le type d'entité ainsi que le bundle cible. Au final, la clé unique de configuration pourra par exemple correspondre à la suivante, pour le type d'entité "node" et le bundle "article": internal_link.internal_link_settings.node.article. C'est pour cette raison que nous avions modifié la clé de base du schéma: internal_link.internal_link_settings.*.* (voir. Ainsi, Drupal peut déterminer que le schéma correspond à tout ce qui commence par internal_link.internal_link_settings., qui contient une première chaîne de caractère, suivie d'un point, suivi d'une autre chaîne de caractère.

Nous aurons également besoin de quelques méthodes statiques, qui vont nous permettre de récupérer la configuration selon le type d'entité et le bundle (loadByEntityTypeBundle), ainsi que de récupérer une sorte de structure de données pour la construction du formulaire de configuration (getFormSpecifications)

Enfin, tous les getter/setter nécessaires pour chaque variable correspondant à un paramètre de configuration.

Voilà le code de notre entité:

/**
 * @file
 * Contains \Drupal\internal_link\Entity\InternalLinkSettings.
 */
 
namespace Drupal\internal_link\Entity;
 
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\internal_link\InternalLinkSettingsInterface;
 
 
/**
 * Defines the InternalLinkSettings entity.
 * 
 * @ConfigEntityType(
 *  id = "internal_link_settings",
 *  label = @Translation("Internal link settings"),
 *  admin_permission = "administer internal link entities",
 *  config_prefix = "internal_link_settings",
 *  entity_keys = {
 *    "id" = "id"
 *  },
 *  list_cache_tags = { "rendered" }
 * )
 */
class InternalLinkSettings extends ConfigEntityBase implements InternalLinkSettingsInterface {
  /**
   * The Internal link settings ID.
   *
   * @var string
   */
  protected $id;
 
  /**
   * The entity type ID (machine name).
   *
   * @var string
   */
  protected $target_entity_type_id;
 
  /**
   * The bundle (machine name).
   *
   * @var string
   */
  protected $target_bundle;
 
 
  /**
   * Is automatic mode enabled
   *
   * @var boolean
   */
  protected $automatic_enabled = FALSE;
 
  /**
   * Is manual mode enabled
   *
   * @var boolean
   */
  protected $manual_enabled = FALSE;
 
  /**
   * Fields to apply internal links
   *
   * @var array
   */
  protected $fields = [];
 
  /**
   * Specific HTML tag to wrap internal link
   *
   * @var string
   */
  protected $wrap_html_tag = '';
 
  /**
   * HTML tags to disallow
   *
   * @var string
   */
  protected $disallowed_html_tags = '[h1] [h2] [h3] [h4] [h5] [h6]';
 
  /**
   * Highlight words instead of transform as link
   *
   * @var boolean
   */
  protected $highlight_words = FALSE;
 
  /**
   * Apply on word boundary
   *
   * @var boolean
   */
  protected $word_boundary = FALSE;
 
  /**
   * Links to process
   *
   * @var number
   */
  protected $links_to_process = 5;
 
  /**
   * Maximum application
   *
   * @var number
   */
  protected $maximum_application = 2;
 
  /**
   * Constructs a InternalLinkSettings object.
   *
   * In most cases, Field entities are created via
   * entity_create('field_config', $values), where $values is the same
   * parameter as in this constructor.
   *
   * @param array $values
   *   An array of the referring entity bundle with:
   *   - target_entity_type_id: The entity type.
   *   - target_bundle: The bundle.
   *   Other array elements will be used to set the corresponding properties on
   *   the class; see the class property documentation for details.
   * @param string $entity_type
   *   The entity type to build.
   *
   * @throws \RuntimeException
   *
   * @see entity_create()
   */
  public function __construct(array $values, $entity_type = 'internal_link_settings') {
    if (empty($values['target_entity_type_id'])) {
      throw new \RuntimeException('Attempt to create content language settings without a target_entity_type_id.');
    }
    if (empty($values['target_bundle'])) {
      throw new \RuntimeException('Attempt to create content language settings without a target_bundle.');
    }
    parent::__construct($values, $entity_type);
  }
 
  /**
   * {@inheritdoc}
   */
  public function id() {
    return $this->target_entity_type_id . '.' . $this->target_bundle;
  }
 
  /**
   * {@inheritdoc}
   */
  public function getTargetEntityTypeId() {
    return $this->target_entity_type_id;
  }
 
 
  /**
   * {@inheritdoc}
   */
  public function getTargetBundle() {
    return $this->target_bundle;
  }
 
  /**
   * {@inheritdoc}
   */
  public function setTargetBundle($target_bundle) {
    $this->target_bundle = $target_bundle;
 
    return $this;
  }
 
 
  /**
   * Get automatic mode state.
   *
   * @return boolean
   */
  public function isAutomaticEnabled() {
    return $this->automatic_enabled;
  }
 
  /**
   * Set automatic mode state.
   *
   * @param boolean $state
   */
  public function setAutomaticEnabled($state) {
    $this->automatic_enabled = $state;
 
    return $this;
  }
 
 
  /**
   * Get manual mode state.
   *
   * ®return boolean
   */
  public function isManualEnabled() {
    return $this->manual_enabled;
  }
 
  /**
   * Set manual mode state.
   *
   * @param boolean $state
   */
  public function setManualEnabled($state) {
    $this->manual_enabled = $state;
 
    return $this;
  }
 
 
  /**
   * Get list of fields the internal links
   * must be applied.
   *
   * @return string[]
   */
  public function getFields() {
    return $this->fields;
  }
 
  /**
   * Set list of fields the internal links
   * must be applied.
   *
   * @param string[] $fields
   */
  public function setFields(array $fields) {
    $this->fields = $fields;
 
    return $this;
  }
 
 
  /**
   * Get the HTML tag to wrap around
   * the internal link.
   *
   * @return string
   */
  public function getWrapHTMLTag() {
    return $this->wrap_html_tag;
  }
 
  /**
   * Set the HTML tag to wrap around
   * the internal link.
   *
   * @param string $wrap_html_tag
   *   A HTML tag. Only tag name, ie H1.
   */
  public function setWrapHTMLTag($wrap_html_tag) {
    $this->wrap_html_tag = $wrap_html_tag;
 
    return $this;
  }
 
 
  /**
   * Get HTML tags disallowed to parse.
   *
   * @return string
   */
  public function getDisallowedHTMLTags() {
    return $this->disallowed_html_tags;
  }
 
  /**
   * Set HTML tags disallowed to parse.
   *
   * @param string
   *   List of disallowed tags
   */
  public function setDisallowedHTMLTags($disallowed_html_tags) {
    $this->disallowed_html_tags = $disallowed_html_tags;
 
    return $this;
  }
 
 
  /**
   * Get highlight word state.
   *
   * @return boolean
   */
  public function getHightlightWords() {
    return $this->highlight_words;
  }
 
  /**
   * Set highlight word state.
   *
   * @param boolean $highlight_words
   */
  public function setHighlightWords($highlight_words) {
    $this->highlight_words = $highlight_words;
 
    return $this;
  }
 
 
  /**
   * Get word boundary state.
   *
   * @return boolean
   */
  public function getWordBoundary() {
    return $this->word_boundary;
  }
 
  /**
   * Set word boundary state.
   *
   * @param boolean $word_boundary
   */
  public function setWordBoundary($word_boundary) {
    $this->word_boundary = $word_boundary;
 
    return $this;
  }
 
 
  /**
   * Get number of links to process.
   * This is the number of different internal links
   * that can be applied on parsing.
   *
   * @return integer
   */
  public function getLinksToProcess() {
    return $this->links_to_process;
  }
 
  /**
   * Set number of links to process.
   * This is the number of different internal links
   * that can be applied on parsing.
   *
   * @param integer $links_to_process
   */
  public function setLinksToProcess($links_to_process) {
    $this->links_to_process = $links_to_process;
 
    return $this;
  }
 
 
  /**
   * Get maximum link application.
   * This is the maximum times the same internal
   * link that can be applied on parsing
   *
   * @return integer
   */
  public function getMaximumApplication() {
    return $this->maximum_application;
  }
 
  /**
   * Set maximum link application.
   *
   * @param integer $maximum_application
   */
  public function setMaximumApplication($maximum_application) {
    $this->maximum_application = $maximum_application;
 
    return $this;
  }
 
 
  /**
   * {@inheritdoc}
   */
  public function preSave(EntityStorageInterface $storage) {
    $this->id = $this->id();
    parent::preSave($storage);
  }
 
  /**
   * {@inheritdoc}
   */
  public function isDefaultConfiguration() {
    return (!$this->automatic_enabled && !$this->manual_enabled);
  }
 
  /**
   * Load specific internal link settings by
   * entity type and bundle.
   *
   * @param string $entity_type_id
   *   The entity type to retrieve configuration.
   * @param string $bundle
   *   The bundle to retrieve configuration.
   *
   * @return \Drupal\internal_link\Entity\InternalLinkSettings
   *   Settings for entity-type/bundle.
   */
  public static function loadByEntityTypeBundle($entity_type_id, $bundle) {
    static $store = [];
 
    // Return null if missing parameter(s)
    if ($entity_type_id == NULL || $bundle == NULL) {
      return NULL;
    }
 
    // Check in store to find already loaded configuration.
    if (!isset($store[$entity_type_id], $store[$entity_type_id][$bundle])) {
 
      // Load configuration switch parameters.
      $config = \Drupal::entityTypeManager()->getStorage('internal_link_settings')->load($entity_type_id . '.' . $bundle);
      if ($config == NULL) {
        // Create new configuration if not exists.
        $config = static::create(['target_entity_type_id' => $entity_type_id, 'target_bundle' => $bundle]);
      }
      $store[$entity_type_id][$bundle] = $config;
    }
    return $store[$entity_type_id][$bundle];
  }
 
  /**
   * Get form specifications settings switch entity type.
   * @param unknown $entity_type
   * @param array $bundles
   */
  private static function getFormSpecificationsByEntityType($entity_type, array $bundles = []) {
    // Initialize some variables
    $labels = [];
    $default = [];
    $internal_link_configuration = [];
    $fields = [];
 
    // Retrieve entity types from system,
    // bundles and fields
    $fields_map = \Drupal::entityManager()->getFieldMap();
 
    if (empty($bundles)) {
      $bundles = \Drupal::entityManager()->getAllBundleInfo();
    }
 
    // Iterate on each entity type and do some checks
    $entity_type_id = $entity_type->id();
 
    // Not a content entity-type ? ignore content-type.
    if (!$entity_type instanceof ContentEntityTypeInterface || !isset($bundles[$entity_type_id])) {
      return NULL;
    }
 
    // No fields ?? ignore content-type.
    if (!isset($fields_map[$entity_type_id])) {
      return NULL;
    }
 
    // Get fields from bundle
    $bundle_fields = [];
    $fields_info = $fields_map[$entity_type_id];
 
    foreach ($fields_info as $field_name => $field_info) {
 
      // Check if at least one field is a long text field
      if (in_array($field_info['type'], ['text_long', 'text_with_summary'])) {
 
        // Store bundle and field informations
        foreach ($field_info['bundles'] as $bundle_name => $bundle) {
          $field_instance = FieldConfig::loadByName($entity_type_id, $bundle_name, $field_name);
          if (isset($field_instance)) {
            if (!isset($bundle_fields[$bundle])) {
              $bundle_fields[$bundle] = [];
            }
            $bundle_fields[$bundle][$field_name] = $field_instance->label();
          }
        }
 
      }
    }
 
    // No long text fields ? ignore content-type.
    if (empty($bundle_fields)) {
      return NULL;
    }
 
    // Store data for fields
    $fields = $bundle_fields;
 
    // Store label and initialize default data
    $labels = $entity_type->getLabel() ?: $entity_type_id;
    $default = [
      'enabled' => FALSE,
    ];
 
    // Iterate on each bundle and retrieve
    // configuration.
    foreach ($bundles[$entity_type_id] as $bundle => $bundle_info) {
 
      $config = static::loadByEntityTypeBundle($entity_type_id, $bundle);
      if (!$config->isDefaultConfiguration()) {
        $default = [
          'enabled' => TRUE,
        ];
      }
 
      // Store configuration if not default.
      $internal_link_configuration[$bundle] = $config;
    }
    //asort($labels);
 
    $result = [
      'labels' => $labels,
      'default' => $default,
      //'bundles' => $bundles,
      'fields' => $fields,
      'configuration' => $internal_link_configuration,
    ];
 
    return $result;
  }
 
  /**
   * Retrieve specifications to build settings form.
   */
  public static function getFormSpecifications() {
 
    // Initialize some variables
    $labels = [];
    $default = [];
    $internal_link_configuration = [];
    $fields = [];
 
    // Retrieve entity types from system,
    // bundles and fields
    $entity_types = \Drupal::entityTypeManager()->getDefinitions();
    $bundles = \Drupal::entityManager()->getAllBundleInfo();
 
    foreach ($entity_types as $entity_type_id => $entity_type) {
      $result = static::getFormSpecificationsByEntityType($entity_type, $bundles);
      if (isset($result)) {
        $labels[$entity_type_id] = $result['labels'];
        $default[$entity_type_id] = $result['default'];
        $fields[$entity_type_id] = $result['fields'];
        $internal_link_configuration[$entity_type_id] = $result['configuration'];
      }
    }
 
    asort($labels);
 
    return [
      $entity_types,
      $labels,
      $default,
      $bundles,
      $fields,
      $internal_link_configuration,
    ];
  }
 
 
  /**
   * {@inheritdoc}
   */
  public function calculateDependencies() {
    parent::calculateDependencies();
 
    // Create dependency on the bundle.
    $entity_type = $this->entityTypeManager()->getDefinition($this->target_entity_type_id);
    $bundle_config_dependency = $entity_type->getBundleConfigDependency($this->target_bundle);
    $this->addDependency($bundle_config_dependency['type'], $bundle_config_dependency['name']);
 
    return $this;
  }
 
  /**
   * Return a new temporary entity to get default values.
   * 
   * @return InternalLinkSettings
   */
  public static function getDefaultConfiguration() {
    return static::loadByEntityTypeBundle('_tmp', '__tmp');
  }
 
  /**
   * Return default configuration values as array
   * 
   * @return array
   */
  public static function getDefaultConfigurationAsArray() {
    $tmp = static::getDefaultConfiguration();
 
    return [
      'automatic_enabled' => $tmp->isAutomaticEnabled(),
      'manual_enabled' => $tmp->isManualEnabled(),
      'fields' => $tmp->getFields(),
      'wrap_html_tag' => $tmp->getWrapHTMLTag(),
      'disallowed_html_tags' => $tmp->getDisallowedHTMLTags(),
      'highlight_words' => $tmp->getHightlightWords(),
      'word_boundary' => $tmp->getWordBoundary(),
      'links_to_process' => $tmp->getLinksToProcess(),
      'maximum_application' => $tmp->getMaximumApplication(),
    ];
  }
}

La méthode la plus importante à comprendre ici est la méthode de chargement d'une configuration spécifique:

  public static function loadByEntityTypeBundle($entity_type_id, $bundle) {
    static $store = [];
 
    // Return null if missing parameter(s)
    if ($entity_type_id == NULL || $bundle == NULL) {
      return NULL;
    }
 
    // Check in store to find already loaded configuration.
    if (!isset($store[$entity_type_id], $store[$entity_type_id][$bundle])) {
 
      // Load configuration switch parameters.
      $config = \Drupal::entityTypeManager()->getStorage('internal_link_settings')->load($entity_type_id . '.' . $bundle);
      if ($config == NULL) {
        // Create new configuration if not exists.
        $config = static::create(['target_entity_type_id' => $entity_type_id, 'target_bundle' => $bundle]);
      }
      $store[$entity_type_id][$bundle] = $config;
    }
    return $store[$entity_type_id][$bundle];
  }

Cette méthode prend en argument le type d'entité et le bundle. Elle tente de récupérer l'entité existante correspondant à ces arguments. Si elle ne la trouve pas, elle va simplement créer une nouvelle entité de configuration pour les arguments donnés, afin que l'entité puisse ensuite être remplie et sauvegardée si l'utilisateur valide son paramétrage.

Les méthodes getFormSpecifications et getFormSpecificationsByEntityType permettent de traiter les informations nécessaires pour la construction du formulaire. Elles récupèrent la liste des champs de type texte disponibles pour un bundle particulier, les labels à utiliser, la configuration en rapport avec chaque type d'entité/bundle, et retourne le tout sous forme d'un tableau qui pourra être utilisé par la suite, comme nous le verrons dans les articles suivants.

Enfin, les méthodes getDefaultConfiguration et getDefaultConfigurationAsArray seront utiles pour récupérer les valeurs par défaut de l'entité, soit sous la forme d'une entité temporaire, soit sous la forme d'un tableau associatif.

Modification du schéma

Le dernier point concerne la modification du schéma de notre entité configurable. Souvenez-vous, nous avions ouvert le fichier YAML /config/schema/internal_link_settings.schema.yml pour l'éditer. Nous allons à nouveau l'éditer pour qu'il corresponde au schéma suivant:

internal_link.internal_link_settings.*.*:
  type: config_entity
  label: 'Internal link settings config'
  mapping:
    id:
      type: string
      label: 'ID'
    target_entity_type_id:
      type: string
      label: 'Entity Type ID'
    target_bundle:
      type:  string
      label: 'Bundle'
    automatic_enabled:
      type: boolean
      label: 'Whether to enable the internal link automatic mode on this node type'
    manual_enabled:
      type: boolean
      label: 'Whether to enable the internal link manual mode on this node type'
    fields:
      type: sequence
      label: 'Available fields'
      sequence:
        type: string
        label: 'Field name'
    wrap_html_tag:
      type: string
      label: 'Wrap HTML tag'
    disallowed_html_tags:
      type: string
      label: 'Disallowed HTML tags'
    highlight_words:
      type: boolean
      label: 'Highlight words'
    word_boundary:
      type: boolean
      label: 'Word boundary'
    links_to_process:
      type: number
      label: 'Links to process'
    maximum_application:
      type: number
      label: 'Link maximum application'

Ici, la logique est toute simple: nous devons simplement indiquer chaque variable de notre entité qui sera sauvegardée sous forme de configuration dans la table "config". Pour chaque variable, nous indiquons le type de variable ainsi qu'un label permettant de comprendre son utilité.

Conclusion

La première étape concernant la configuration globale est terminée. Nous avons maintenant une entité de type configuration qui est implémentée et qui va nous permettre de stocker le paramétrage pour chaque type d'entité/bundle sur lesquels nous voudront rattacher les liens internes. Les articles suivants traiteront de la manière d'utiliser cette entité, en liaison avec un élément de formulaire spécifiquement développé pour et le formulaire de configuration du type d'entité internal_link.

Vous avez pu constater que pour cette étape, Drupal Console n'a pas été d'une grande aide car nous n'avions besoin que d'un petit fragment de la génération.

Ajouter un commentaire

CAPTCHA
Cette question permet de savoir si vous êtes un visiteur ou un robot de soumission de spams