Wie aktualisiere ich die Konfiguration eines Moduls?


33

Ich erstelle ein benutzerdefiniertes Modul in Drupal 8. Es enthält einige YAML-Konfigurationsdateien.

Während der Entwicklung muss ich die Konfiguration ändern und ergänzen, z. B. um ein weiteres Feld zu meiner benutzerdefinierten Entität hinzuzufügen.

Derzeit habe ich nur die Möglichkeit gefunden, Drupal auf die Änderungen aufmerksam zu machen, indem ich das Modul deinstalliere und erneut installiere.

Gibt es eine Möglichkeit, Drupal zu veranlassen, zu überprüfen, ob die von Modulen bereitgestellten Konfigurationsdateien mit der aktiven Konfiguration identisch sind, und wenn nicht, die aktive Konfiguration zu aktualisieren? Wie werden Modulupdates gehandhabt? In D7 hook_update_Nwürde verwendet, um Felder mit PHP hinzuzufügen, aber es sieht so aus, als sollte dies vom CM in D8 behandelt werden?

Dinge, die ich versucht habe, nachdem ich die yml-Dateien im Modul aktualisiert habe:

  1. drush cr, Config Sync.

  2. Manuelles Kopieren aller aktualisierten Konfigurationsdateien nach sites/default/files/config_XXX/staging/- dies führt jedoch zu dem Fehler "Die bereitgestellte Konfiguration kann nicht importiert werden, da sie von einer anderen Site als dieser Site stammt. Sie können die Konfiguration nur zwischen geklonten Instanzen dieser Site synchronisieren." .

  3. Manuelles Importieren der Dateien nacheinander mit dem Konfigurationsmanager. Das funktioniert, aber natürlich muss es einen automatischeren Weg geben.

  4. [EDIT] Verwenden Sie das config_update- Modul manuell , um Änderungen zu überprüfen und die Konfiguration des Moduls wiederherzustellen . Auch dies ist manuell.

BEARBEITEN: Vom Verwalten der Konfiguration - Tun und Verbieten

NICHT

Versuchen Sie, die aktive Konfiguration auf Ihrer Site zu ändern, indem Sie die Dateien im Konfigurations- / Installationsverzeichnis eines Moduls ändern. Dies funktioniert NICHT, da Drupal nur dann aus diesem Verzeichnis liest, wenn das Modul installiert ist.

... ändert aber es sind gehen passieren, es sei denn , Module gebunden sind , was auch immer Config sie in ihrem ersten Release erforderlich und aktualisieren nie oder Config hinzuzufügen.

Danke im Voraus.


Ich denke, etwas sehr Ähnliches wurde vorher gefragt (kann es jetzt nicht ganz finden), und ich denke, die Antwort war, dass die Standardkonfiguration nur zum Zeitpunkt der Installation abgefragt wird, also ist eine Neuinstallation der richtige Weg. Zitiere mich aber nicht :)
Clive

1
'k, aber wie würde ein Modul aktualisiert werden? Module dürfen Updates in D8 bekommen, oder? Es muss eine Möglichkeit (a la config_update) geben, damit Module sagen: "Drupal! Ich benötige jetzt diese zusätzliche Konfiguration, schau sie dir an und füge sie bitte zusammen."
Artfulrobot

Configuration Update Manager erledigt den Job, aber ich bin damit einverstanden, dass es eine systemeigene Möglichkeit gibt, dies zu tun. Etwas in hook_update_Nwürde ich annehmen, aber ich bin nicht sicher, was
Clive

2
Wow, ich denke die Antwort könnte lauten "du kannst nicht"! Ich habe das nie kommen sehen! Zurück zu hook_update_N. Hervorragender Artikel über Drupal 8 für kleine Websites (und Teil 2 ). In D8 "besitzen Sites ihre Konfiguration, keine Module" .
Artfulrobot

Ich möchte hinzufügen, dass ein hervorragender Anwendungsfall dafür ein Multisite-Setup ist, bei dem Sie bestimmte große Teile der Konfiguration, aber nicht alle, freigeben und bereitstellen möchten. Dies können benutzerdefinierte Module sein. Für eine einzelne Site wäre es einfach ein Konfigurations-Export / -Import, eine Multisite wäre nicht so einfach.
Ambidex

Antworten:


24

Wie in der ursprünglichen Frage und den nachfolgenden Kommentaren erwähnt, gibt es eine Vielzahl von Contrib-Modulen und manuellen Methoden, um dies zu erreichen.

Es automatisch oder auf eine benutzerdefinierte Art und Weise zu tun, ist meiner Meinung nach hook_update_N()immer noch die wahrscheinlich praktikabelste Option.

Dies ist beispielsweise ein Beispiel für die Aktualisierung des Head 2 Head, um Folgendes system.sitefestzulegen default_langcode:

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

Sie können auch die Konfiguration einlesen (empfohlen nur zum Hinzufügen einer neuen Konfiguration, nicht unbedingt zum Aktualisieren oder Überschreiben der Konfiguration, die möglicherweise angepasst wurde):

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

wo $pathist der absolute Pfad zur my_config.foo.ymlDatei.


1
Wenn ich dem zweiten Ansatz folge, wird die Konfiguration in Drupal geschrieben, erhält aber keine UUID, selbst wenn ich sie in das Konfigurationsverzeichnis exportiere. Dies führte mich zu einem Problem, bei dem ich dies mit einer benutzerdefinierten Ansicht versuchte. Die Übersichtsseite "Ansichten" hat einen schwerwiegenden Fehler zurückgegeben, da die UUID für die Entität "Config" nicht verfügbar war.
Sebastian

9

Da ich auch auf diese Frage gestoßen bin, aber hier nicht die richtige Antwort für meine Situation gefunden habe, möchte ich eine weitere Antwort hinzufügen.

Bitte beachten Sie: Anti-Pattern voraus!

Anwendungsfall

Wenn wir Projekte entwickeln, aktualisieren wir unsere Test- / Akzeptanzumgebung ständig mit neuen Konfigurationsaktualisierungen. Nehmen wir zum Beispiel ein einfaches fiktives News-Modul, wir möchten dem Modul einen Inhaltstyp hinzufügen und diesen in unserer Akzeptanzumgebung bereitstellen. Nach der Überprüfung sind wir zu dem Schluss gekommen, dass einige Felder fehlen und andere Dinge, die sich auf die Konfiguration beziehen. Da wir wissen, dass die Akzeptanzumgebung in der Konfiguration nicht aktualisiert wird, möchten wir wirklich nur die gesamte Konfiguration aus dem Modul neu laden, während neue Funktionen hinzugefügt werden, und nicht durch den Import jeder geänderten .ymlDatei gestört werden .

Wir brauchen unsere Konfiguration nur in Modulen, wenn wir Multisites entwickeln. Für einzelne Sites verwenden wir meist nur die exportierte Site-Konfiguration, bei der der nächste Schritt nicht erforderlich ist.

Konfiguration komplett neu importieren (Anti-Pattern!)

Wir haben festgestellt, dass wir mithilfe des ConfigInstaller- Dienstes die vollständige Konfiguration von einem bestimmten Modul erneut importieren können.

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

Mit Vorsicht verwenden!

Ich möchte hinzufügen, dass dadurch alle aktiven Inhalte überschrieben werden, die in der Umgebung geändert wurden. Verwenden Sie diese Lösung daher nur, wenn Sie sicher sind, dass die aktive Konfiguration überschrieben werden kann. Wir werden dies niemals in einer Produktionsumgebung verwenden und nur in der frühen Entwicklung anwenden.

Probieren Sie zuerst die Lösung von @ jhedstrom aus, bevor Sie diese in Betracht ziehen.


9

Ich habe diese Gist auf GitHub gefunden, die die Konfiguration eines bestimmten Moduls mit drush zurücksetzt / neu lädt:

drush cim -y --partial --source=modules/path/to/module/config/install/

2

Basierend auf meinem Kommentar: Wie aktualisiere ich die Konfiguration eines Moduls?

Wenn ich dem zweiten Ansatz folge, wird die Konfiguration in Drupal geschrieben, erhält aber keine UUID, selbst wenn ich sie in das Konfigurationsverzeichnis exportiere. Dies führte mich zu einem Problem, bei dem ich dies mit einer benutzerdefinierten Ansicht versuchte. Die Ansichtsübersichtsseite hat einen schwerwiegenden Fehler zurückgegeben, da die UUID für die Config-Entität nicht verfügbar war.

Ich habe eine kleine Funktion erstellt, die mir dabei hilft, hier mein Beispielcode:

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

1

Die obige Antwort (vollständiger Neuimport) hat auch für meinen Anwendungsfall funktioniert, aber zuerst habe ich ein wenig über einen selektiveren Neuimport nachgedacht. Hier ist der Code, den ich hatte, der als Update-Hook zu funktionieren schien und der auf dem Code im config_update-Modul basierte:

/**
 * 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

Das Configuration Synchronizer- Modul hilft dabei, dieses Problem auf nette Weise zu lösen. Diese Modulsuite mit 7 Modulen scheint nur für diesen Fall etwas übertrieben zu sein (es ist hauptsächlich beabsichtigt, Updates sicher zusammenzuführen, ohne Anpassungen zu überschreiben), aber aufgrund ihres Konzepts können auch Konfigurationsänderungen von den Modulen / install und nachverfolgt und importiert werden / optionale Ordner schnell.

Grundsätzlich können Sie es wie folgt testen:

  • Erstellen und aktivieren Sie Ihr benutzerdefiniertes Modul in Ihrer lokalen Umgebung, indem Sie einige "Standard" -Konfigurationselemente wie gewohnt im Ordner "/ config / install" ablegen
  • Installieren und aktivieren Sie das config_sync-Modul und alle abhängigen Module
  • Nehmen Sie einige Änderungen im Konfigurationselement Ihres Moduls im Ordner / config / install vor
  • access / admin / config / development / configuration / distro. Sie sollten Ihre Änderung sehen und die Option haben, sie in die aktive Konfiguration zu importieren (der Merge-Modus soll die Client-Änderungen beibehalten, der Reset-Modus erzwingt den Import). Während der Entwicklung verwende ich hauptsächlich den Reset-Modus, aber der Merge-Modus sollte auch funktionieren, sofern Sie dies nicht tun Parallel dazu wurden manuelle Änderungen an derselben Konfiguration vorgenommen

Hinweis: Wenn Sie config_sync nur verwenden möchten, um den Konfigurationsimport während der Modulentwicklung zu beschleunigen (und sich nicht um das Zusammenführen mit Client-Updates kümmern möchten), ist es ausreichend, diese Suite nur in Ihrer lokalen (Entwicklungs-) Umgebung zu installieren und zu aktivieren ( vorausgesetzt, Ihr Modul wechselt nach dem Abschluss in eine höhere Umgebung und Sie verwenden das D8-Kernkonfigurationsmanagement, um die Konfiguration in eine höhere Umgebung zu übertragen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.