Comment mettre à jour la configuration d'un module?

33

Je construis un module personnalisé dans Drupal 8. Il comprend des fichiers de configuration YAML.

Au fur et à mesure que je développe, j'ai besoin de changer et d’ajouter à la configuration, par exemple pour ajouter un autre champ à mon entité personnalisée.

À l'heure actuelle, le seul moyen que j'ai trouvé pour que Drupal remarque les modifications est de désinstaller le module, puis de le réinstaller.

Existe-t-il un moyen de permettre à Drupal de vérifier que les fichiers de configuration fournis par les modules sont identiques à la configuration active et, dans le cas contraire, de mettre à jour la configuration active? Comment sont gérées les mises à jour de modules? Dans D7 hook_update_Nserait utilisé pour ajouter des champs en utilisant PHP, mais il semble que cela devrait être géré par le CM dans D8?

Ce que j'ai essayé après la mise à jour des fichiers yml du module:

  1. drush cr, config sync.

  2. copier manuellement tous les fichiers de configuration mis à jour dans sites/default/files/config_XXX/staging/- mais cela donne cette erreur "La configuration intermédiaire ne peut pas être importée, car elle provient d'un site différent de celui de ce site. Vous ne pouvez synchroniser la configuration qu'entre des instances clonées de ce site." .

  3. importer manuellement les fichiers un à un à l’aide du gestionnaire de configuration. Cela fonctionne, mais évidemment, il doit y avoir un moyen plus automatique.

  4. [EDIT] utilise manuellement le module config_update pour examiner les modifications et «revenir» à la configuration du module. Encore une fois, c'est manuel.

EDIT: à partir de la gestion de la configuration - à faire et à ne pas faire

Ne pas faire

Essayez de modifier la configuration active sur votre site en modifiant les fichiers du répertoire config / install du module. Cela ne fonctionnera PAS car Drupal ne lira que dans ce répertoire lors de l'installation du module.

... mais des changements vont se produire, à moins que les modules ne soient liés à la configuration dont ils ont besoin dans leur toute première version, et ne puissent jamais jamais mettre à jour ou ajouter une configuration.

Merci d'avance.

artfulrobot
la source
Je pense que quelque chose de très similaire a déjà été demandé (je ne le trouve pas tout à fait maintenant), et je pense que la réponse a été que la configuration par défaut est uniquement consultée au moment de l'installation, la réinstallation est donc la voie à suivre. Ne me citez pas cependant :)
Clive
1
'k, mais comment un module serait-il mis à jour? Les modules sont autorisés à obtenir des mises à jour en D8, non ;-)? Il doit y avoir un moyen (à la config_update) pour les modules de dire "Drupal! J'ai maintenant besoin de cette configuration supplémentaire, jetez-y un coup d'oeil et fusionnez-la s'il vous plaît."
artfulrobot
Configuration Update Manager fait le travail, mais je conviens qu’il devrait exister un moyen natif de le faire. Quelque chose dedans hook_update_Nje suppose, mais je ne sais pas trop quoi
Clive
2
Wow, je pense que la réponse pourrait être "tu ne peux pas"! Jamais vu ça venir! Retour à hook_update_N. Excellent article sur Drupal 8 pour les petits sites (et la partie 2 ). Dans D8, "les sites possèdent leur configuration, pas leurs modules" .
artfulrobot
J'aimerais ajouter qu'un excellent cas d'utilisation pour cela est une configuration multisite, dans laquelle vous souhaitez partager de gros éléments de configuration spécifiques mais pas tous et les déployer. Ceux-ci peuvent inclure des modules personnalisés. Pour un site unique, il s'agirait simplement d'une exportation / importation de configuration, un multisite ne serait pas si simple.
Ambidex

Réponses:

24

Comme mentionné dans la question initiale et dans les commentaires de suivi, il existe une variété de modules contrib et de méthodes manuelles pour accomplir cela.

Le faire automatiquement, ou de manière personnalisée, hook_update_N()reste probablement l’option la plus viable.

Par exemple, voici un exemple de Head 2 Head à mettre system.siteà jour pour définir le default_langcode:

  $config_factory = \Drupal::configFactory();
  $langcode = $config_factory->get('system.site')->get('langcode');
  $config_factory->getEditable('system.site')->set('default_langcode', $langcode)->save();

Vous pouvez également lire dans config (recommandé uniquement pour ajouter une nouvelle configuration, pas nécessairement pour mettre à jour ou remplacer une configuration pouvant avoir été personnalisée):

  $source = new FileStorage($path);
  /** @var \Drupal\Core\Config\StorageInterface $active_storage */
  $active_storage = \Drupal::service('config.storage');
  $active_storage->write($name, $source->read($name));

$pathest le chemin absolu du my_config.foo.ymlfichier.

jhedstrom
la source
1
Lorsque je suis la deuxième approche, la configuration est écrite dans Drupal mais ne reçoit pas d’UUID même lorsque je l’exporte dans le répertoire config. Cela m'a conduit à un problème où j'ai essayé cela avec une vue personnalisée. La page de présentation Vues m'a renvoyé une erreur irrécupérable, étant donné que l'uid de l'entité de configuration n'était pas disponible.
Sébastien
9

Comme je me posais aussi sur cette question mais ne trouvant pas vraiment la réponse correcte à ma situation ici, j'aimerais ajouter une autre réponse.

Remarque: Anti-pattern ahead!

Cas d'utilisation

Lorsque nous développons des projets, nous mettons constamment à jour notre environnement de test / acceptation avec les nouvelles mises à jour de configuration. Prenons par exemple un simple module News fictif, nous aimerions ajouter un type de contenu au module et le déployer dans notre environnement d'acceptation. Après examen, nous avons conclu qu’il restait quelques champs et d’autres éléments relatifs à la configuration. Sachant que l'environnement d'acceptation n'est pas mis à jour dans config, nous souhaitons uniquement recharger l'intégralité de la configuration à partir du module, tout en ajoutant de nouvelles fonctionnalités, sans être dérangé par l'importation de chaque .ymlfichier modifié .

Nous n'avons besoin de notre configuration en modules que lorsque nous développons des sites multiples. Pour les sites uniques, nous utilisons principalement la configuration de site exporté dans laquelle l'étape suivante n'est pas nécessaire.

Réimportez entièrement la configuration (anti-pattern!)

Nous avons constaté qu'en utilisant le service ConfigInstaller , nous pouvions réimporter à nouveau la configuration complète à partir d'un module spécifique.

// Implement in a update_N hook. 
\Drupal::service('config.installer')->installDefaultConfig('module', $module);

Utiliser avec précaution!

J'aimerais ajouter que cela écrasera tout contenu actif qui a été modifié dans l'environnement. Donc, utilisez cette solution uniquement lorsque vous êtes sûr que vous pouvez écraser la configuration active en toute sécurité. Nous ne l'utilisons jamais dans un environnement de production et nous ne l'appliquerons qu'au début du développement.

Essayez d’abord la solution de @ jhedstrom avant d’envisager celle-ci.

Ambidex
la source
9

J'ai trouvé ce Gist sur GitHub, qui rétablit / recharge la configuration du module à l'aide de drush:

drush cim -y --partial --source=modules/path/to/module/config/install/
Елин Й.
la source
2

Basé sur mon commentaire: Comment mettre à jour la configuration d'un module?

Lorsque je suis la deuxième approche, la configuration est écrite dans Drupal mais ne reçoit pas d’UUID même lorsque je l’exporte dans le répertoire config. Cela m'a conduit à un problème où j'ai essayé cela avec une vue personnalisée. La page de présentation Vues m'a renvoyé une erreur irrécupérable, étant donné que l'uid de l'entité de configuration n'était pas disponible.

J'ai créé une petite fonction qui m'aide avec ça, voici mon exemple de code:

function _example_views_update_config($configsNames) {
  $config_path    = drupal_get_path('module', 'example') . '/config/install';
  $source         = new FileStorage($config_path);
  $config_storage = \Drupal::service('config.storage');
  $config_factory = \Drupal::configFactory();
  $uuid_service = \Drupal::service('uuid');

  foreach ($configsNames as $name) {
    $config_storage->write($name, $source->read($name));
    $config_factory->getEditable($name)->set('uuid', $uuid_service->generate())->save();
  }
}

/**
 * Add new action configurations.
 */
function example_update_8003() {
  $configsNames = [
    'config-1',
    'config-2',
  ];

  _example_views_update_config($configsNames);
  return 'Added new configurations.';
}
Sebastian
la source
1

La réponse ci-dessus (réimportation intégrale) a également fonctionné pour mon cas d'utilisation, mais j'ai d'abord passé un peu de temps à rechercher une réimportation plus sélective. Voici le code que j'avais qui semblait fonctionner comme un crochet de mise à jour et était basé sur le code du module config_update:

/**
 * Update all my config.
 *
 * This can be more selective than calling installDefaultConfig().
 */
function MYMODULE_update_8004() {
  $prefixes = [
    'field.storage.node',
    'field.field.node',
    'node.type',
    'core.base_field_override.node',
    'core.entity_view_display'
  ];
  $results = [];
  foreach ($prefixes as $prefix) {
    $results[$prefix] = _update_or_install_config($prefix);
  }
  $return = '';
  foreach ($results as $prefix => $result) {
    $return .= "\n$prefix:\n";
    foreach ($result as $key => $ids) {
      $return .= "$key: " . implode(', ', $ids) . "\n";
    }
  }
  if (function_exists('drush_log')) {
    drush_log($return, \Psr\Log\LogLevel::WARNING);
  }
  return $return;
}


/**
 * Update or install config entities from config/install files.
 *
 * @see \Drupal\config_update\ConfigReverter::import
 * @see \Drupal\config_update\ConfigReverter::revert
 *
 * @param string $prefix
 *   The prefix for YAML files in find, like 'field.storage.node'
 */
function _update_or_install_config($prefix) {
  $updated = [];
  $created = [];
  /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manger */
  $config_manger = \Drupal::service('config.manager');
  $files = glob(__DIR__ . '/config/install/' . $prefix . '.*.yml');
  foreach ($files as $file) {
    $raw = file_get_contents($file);
    $value = \Drupal\Component\Serialization\Yaml::decode($raw);
    if (!is_array($value)) {
      throw new \RuntimeException(sprintf('Invalid YAML file %s'), $file);
    }
    // Lazy hack here since that code ignores the file extension.
    $type = $config_manger->getEntityTypeIdByName(basename($file));
    $entity_manager = $config_manger->getEntityManager();
    $definition = $entity_manager->getDefinition($type);
    $id_key = $definition->getKey('id');
    $id = $value[$id_key];
    /** @var \Drupal\Core\Config\Entity\ConfigEntityStorage $entity_storage */
    $entity_storage = $entity_manager->getStorage($type);
    $entity = $entity_storage->load($id);
    if ($entity) {
      $entity = $entity_storage->updateFromStorageRecord($entity, $value);
      $entity->save();
      $updated[] = $id;
    }
    else {
      $entity = $entity_storage->createFromStorageRecord($value);
      $entity->save();
      $created[] = $id;
    }
  }
  return [
    'updated' => $updated,
    'created' => $created,
  ];
}
pwolanin
la source
1

Le module Configuration Synchronizer aide à résoudre ce problème de manière agréable. Cette suite de modules de 7 modules semble être un peu surchargée juste pour ce cas (son intention est principalement de fusionner en toute sécurité dans des mises à jour sans écraser les personnalisations), mais en raison de son concept, elle permet également de suivre et d'importer les modifications de configuration du module / install et / dossiers optionnels rapidement.

En gros, vous pouvez le tester comme suit:

  • créez et activez votre module personnalisé sur votre environnement local avec des éléments de configuration "par défaut" placés dans le dossier / config / install, comme d'habitude
  • installer et activer le module config_sync et tous ses modules dépendants
  • faire des modifications dans l'élément de configuration de votre module à l'intérieur du dossier / config / install
  • accès / admin / config / développement / configuration / distribution. Vous devriez voir votre modification et pouvoir l’importer dans la configuration active (le mode de fusion sert à préserver les modifications du client, le mode de réinitialisation force l’importation). Pendant le développement, je vais surtout utiliser le mode de réinitialisation, mais le mode de fusion devrait également fait des changements manuels dans la même configuration en parallèle

Remarque: si vous souhaitez uniquement utiliser config_sync pour accélérer l’importation de la configuration lors du développement du module (sans vous soucier de la fusion avec les mises à jour du client), il suffit que cette suite soit installée et activée sur votre environnement local (de développement) ( en supposant que votre module ira dans des environnements supérieurs après la finalisation et que vous utilisez la gestion de configuration D8 pour envoyer sa configuration dans des environnements supérieurs).

Mirsoft
la source