web-dev-qa-db-fra.com

Comment mettre à jour la configuration d'un module?

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

Au fur et à mesure que je développe, je dois changer et ajouter à la configuration, par ex. pour ajouter un autre champ à mon entité personnalisée.

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

Existe-t-il un moyen d'obtenir Drupal pour vérifier que les fichiers de configuration fournis par les modules sont les mêmes que la configuration active, et sinon, mettre à jour la configuration active? Comment les mises à jour des modules sont-elles gérées? En D7 hook_update_N serait utilisé pour ajouter des champs en utilisant PHP, mais il semble que cela devrait être géré par le CM en D8?

Ce que j'ai essayé après avoir mis à jour les fichiers yml dans le 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 ce site. Vous ne pouvez synchroniser la configuration qu'entre des instances clonées de ce site.".

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

  4. [MODIFIER] utilisez manuellement le module config_update pour inspecter les modifications et "revenir" à la configuration du module. Encore une fois, c'est manuel.

EDIT: De Gestion de la configuration - à faire et à ne pas faire

À NE PAS FAIRE

Essayez de changer la configuration active sur votre site en changeant les fichiers dans le répertoire config/install d'un module. Cela ne fonctionnera PAS car Drupal ne lira à partir de ce répertoire que lorsque le module sera installé.

... mais des changements sont à prévoir en cours, à moins que les modules ne soient liés à la configuration dont ils avaient besoin dans leur toute première version et qu'ils ne mettent jamais à jour ou ajoutent de configuration.

Merci d'avance.

32
artfulrobot

Comme mentionné dans la question d'origine et les commentaires de suivi, il existe une variété de modules contrib et de méthodes manuelles pour y parvenir.

Pour le faire automatiquement ou de façon personnalisée, je pense que hook_update_N() est probablement toujours l'option la plus viable.

Par exemple, ceci est un exemple de Head 2 Head pour mettre à jour system.site 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 mettre à jour ou remplacer la configuration qui peut 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));

$path est le chemin absolu vers le my_config.foo.yml fichier.

24
jhedstrom

J'ai trouvé ce Gist sur GitHub, qui inverse/recharge la configuration du module donnée en utilisant drush:

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

Comme j'ai atterri sur cette question également mais que je n'ai pas vraiment trouvé la bonne réponse à ma situation ici, j'aimerais ajouter une autre réponse.

Veuillez noter: Anti-pattern à venir!

Cas d'utilisation

Lorsque nous développons des projets, nous mettons constamment à jour notre environnement de test/acceptation avec de 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 manque quelques champs et d'autres éléments liés à la configuration. Puisque nous savons que l'environnement d'acceptation n'est pas mis à jour dans config, nous voulons vraiment seulement recharger la configuration entière depuis le module tout en ajoutant de nouvelles fonctionnalités et ne pas être dérangé en important chaque _ .yml fichier.

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

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

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

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

Utiliser avec précaution!

Je voudrais ajouter que cela écrasera tout contenu actif qui a été modifié dans l'environnement. Donc, n'utilisez cette solution que lorsque vous êtes sûr qu'il est sûr d'écraser la configuration active. Nous ne l'utiliserons jamais sur un environnement de production et ne s'appliquerons qu'au début du développement.

Essayez d'abord la solution de @ jhedstrom avant de commencer à considérer celle-ci.

10
Ambidex

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 n'obtient 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 un Vue personnalisée. La page de vue d'ensemble des vues m'a renvoyé une erreur fatale car l'uuid de l'entité Config 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.';
}
2
Sebastian

La réponse ci-dessus (réimportation complète) a également fonctionné pour mon cas d'utilisation, mais j'ai d'abord passé un peu de temps à étudier 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,
  ];
}
1
pwolanin

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

Fondamentalement, 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 quelques modifications dans l'élément de configuration de votre module à l'intérieur du dossier/config/install
  • accéder à/admin/config/development/configuration/distro. Vous devriez voir votre modification et avoir la possibilité de l'importer dans la configuration active (le mode de fusion est destiné à préserver les modifications du client, le mode de réinitialisation force l'importation) - pendant le développement, j'utiliserai principalement le mode de réinitialisation, mais le mode de fusion devrait également fonctionner sauf si vous a fait des changements manuels dans la même configuration en parallèle

Remarque: si vous seulement souhaitez utiliser config_sync pour accélérer l'importation de configuration pendant le développement du module (et que vous ne vous souciez pas de la fusion avec les mises à jour client), il suffit que cette suite soit installée et activée sur votre environnement local (développement) uniquement (en supposant que votre module ira dans des environnements plus élevés après la finalisation et que vous utiliserez la gestion de configuration du noyau D8 pour publier sa configuration dans des environnements plus élevés).

1
Mirsoft