Come aggiorno la configurazione di un modulo?


33

Sto costruendo un modulo personalizzato in Drupal 8. Include alcuni file di configurazione YAML.

Durante lo sviluppo, devo modificare e aggiungere la configurazione, ad esempio per aggiungere un altro campo alla mia entità personalizzata.

Al momento l'unico modo per trovare Drupal che nota le modifiche è disinstallare il modulo e reinstallarlo.

C'è un modo per convincere Drupal a verificare che i file di configurazione forniti dai moduli siano gli stessi della configurazione attiva e, in caso contrario, aggiornare la configurazione attiva? Come vengono gestiti gli aggiornamenti dei moduli? In D7 hook_update_Nsarebbe usato per aggiungere campi usando PHP, ma sembra che questo dovrebbe essere gestito dal CM in D8?

Cose che ho provato dopo aver aggiornato i file yml nel modulo:

  1. drush cr, config sync.

  2. copiando manualmente tutti i file di configurazione aggiornati in sites/default/files/config_XXX/staging/- ma questo dà questo errore "La configurazione a fasi non può essere importata, perché proviene da un sito diverso da questo sito. Puoi sincronizzare la configurazione solo tra istanze clonate di questo sito." .

  3. importando manualmente i file uno ad uno usando il config manager. Funziona, ma ovviamente ci deve essere un modo più automatico.

  4. [EDIT] usa manualmente il modulo config_update per ispezionare le modifiche e "ripristinare" la configurazione del modulo. Ancora una volta, questo è manuale.

MODIFICA: Da Gestione della configurazione - cosa fare e cosa non fare

DA EVITARE

Prova a cambiare la configurazione attiva sul tuo sito modificando i file nella directory config / install di un modulo. Questo NON funzionerà perché Drupal leggerà da quella directory solo quando il modulo è installato.

... ma i mutamenti ci sono andando ad accadere, a meno che i moduli sono tenuti a tutto ciò di cui avevano bisogno config nel loro primo rilascio, e non può mai mai aggiornare o aggiungere config.

Grazie in anticipo.


Penso che sia stato chiesto qualcosa di molto simile prima (non riesco a trovarlo ora), e penso che la risposta sia stata che la configurazione predefinita è stata consultata solo al momento dell'installazione, quindi la reinstallazione è la strada da percorrere. Non citarmi però :)
Clive

1
'k, ma come verrebbe aggiornato un modulo? I moduli possono ottenere aggiornamenti in D8, giusto ;-)? Deve esserci un modo (alla config_update) per i moduli di dire "Drupal! Ora ho bisogno di questa configurazione extra, dai un'occhiata e fondila per favore."
artfulrobot,

Configuration Update Manager fa il lavoro, ma sono d'accordo che ci dovrebbe essere un modo nativo per farlo. hook_update_NPresumo che ci sia qualcosa , ma non sono sicuro di cosa
Clive

2
Wow, penso che la risposta potrebbe finire per essere "non puoi"! Non l'ho mai visto arrivare! Torna a hook_update_N. Ottimo articolo su Drupal 8 per piccoli siti (e parte 2 ). In D8 "i siti possiedono la loro configurazione, non i moduli" .
artfulrobot,

Vorrei aggiungere che un eccellente caso d'uso per questo è un'installazione multi-sito, in cui si desidera condividere specifici pezzi di configurazione di grandi dimensioni ma non tutti e distribuire questo. Questi potrebbero includere moduli personalizzati. Per un singolo sito sarebbe semplicemente una configurazione di esportazione / importazione, un multisito non sarebbe così semplice.
Ambidex,

Risposte:


24

Come menzionato nella domanda originale e nei commenti di follow-up, ci sono una varietà di moduli contrib e metodi manuali per raggiungere questo obiettivo.

Per farlo automaticamente o in modo personalizzato, penso che hook_update_N()sia ancora probabilmente l'opzione più praticabile.

Ad esempio, questo è un esempio di Head 2 Head da aggiornare system.siteper impostare default_langcode:

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

Puoi anche leggere in config (consigliato solo per aggiungere una nuova configurazione, non necessariamente aggiornando o ignorando la configurazione che potrebbe essere stata personalizzata):

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

dove $pathè il percorso assoluto del my_config.foo.ymlfile.


1
Quando sto seguendo il secondo approccio, la configurazione viene scritta in Drupal ma non viene visualizzato un UUID anche quando lo esporto nella directory di configurazione. Questo mi ha portato a un problema in cui l'ho provato con una vista personalizzata. La pagina della panoramica di Views mi ha restituito un errore irreversibile poiché l'Uuid per l'entità Config non era disponibile.
Sebastian

9

Dato che sono arrivato anche a questa domanda, ma non ho trovato la risposta corretta per la mia situazione, vorrei aggiungere un'altra risposta.

Nota: anti-pattern avanti!

Caso d'uso

Quando sviluppiamo progetti, aggiorniamo costantemente il nostro ambiente di test / accettazione con nuovi aggiornamenti di configurazione. Prendiamo ad esempio un semplice modulo di notizie fittizio, vorremmo aggiungere un tipo di contenuto al modulo e distribuirlo nel nostro ambiente di accettazione. Dopo la revisione, abbiamo concluso che mancano alcuni campi e altre cose relative alla configurazione. Poiché sappiamo che l'ambiente di accettazione non viene aggiornato in config, vogliamo davvero ricaricare l'intera configurazione dal modulo mentre sono state aggiunte nuove funzionalità e non essere disturbati dall'importazione di ogni .ymlfile modificato .

Abbiamo solo bisogno della nostra configurazione in moduli quando sviluppiamo siti multipli. Per i singoli siti, utilizziamo principalmente solo la configurazione dei siti esportati in cui il passaggio successivo non è necessario.

Reimport config interamente (anti-pattern!)

Abbiamo scoperto che utilizzando il servizio ConfigInstaller , siamo in grado di reimportare nuovamente la configurazione completa da un modulo specifico.

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

Usare con cautela!

Vorrei aggiungere che questo sovrascriverà qualsiasi contenuto attivo che è stato modificato nell'ambiente. Quindi, utilizzare questa soluzione solo quando si è sicuri che sia sicuro sovrascrivere la configurazione attiva. Non lo useremo mai in un ambiente di produzione e lo applicheremo solo nei primi sviluppi.

Prima prova la soluzione di @ jhedstrom prima di iniziare a considerare questa.


9

Ho trovato questo Gist su GitHub, che ripristina / ricarica la configurazione del modulo data usando drush:

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

2

Sulla base del mio commento: come posso aggiornare la configurazione di un modulo?

Quando sto seguendo il secondo approccio, la configurazione viene scritta in Drupal ma non viene visualizzato un UUID anche quando lo esporto nella directory di configurazione. Questo mi ha portato a un problema in cui l'ho provato con una vista personalizzata. La pagina della panoramica di Views mi ha restituito un errore irreversibile poiché l'Uuid per l'entità Config non era disponibile.

Ho creato una piccola funzione che mi aiuta in questo, qui il mio codice di esempio:

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

La risposta sopra (reimportazione completa) ha funzionato anche per il mio caso d'uso, ma prima ho trascorso un po 'a esaminare una reimportazione più selettiva. Ecco il codice che avevo che sembrava funzionare come hook di aggiornamento ed era basato sul codice nel modulo 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

Il modulo Configuration Synchronizer aiuta a risolvere questo problema in modo piacevole. Questa suite di moduli da 7 moduli sembra essere un po 'eccessiva solo per questo caso (la sua intenzione è principalmente quella di unire in sicurezza gli aggiornamenti senza sovrascrivere le personalizzazioni), ma grazie al suo concetto consente anche di tracciare e importare le modifiche di configurazione dal modulo / installa e / cartelle opzionali rapidamente.

Fondamentalmente, puoi provarlo come segue:

  • creare e abilitare il modulo personalizzato nell'ambiente locale con alcuni elementi di configurazione "predefiniti" inseriti nella cartella / config / install come al solito
  • installa e abilita il modulo config_sync e tutti i suoi moduli dipendenti
  • fai alcune modifiche nella voce di configurazione del tuo modulo all'interno della cartella / config / install
  • accesso / admin / config / development / configuration / distro. Dovresti vedere la tua modifica e avere l'opzione di importarla nella configurazione attiva (la modalità Unisci ha lo scopo di preservare le modifiche del client, la modalità Reimposta forza l'importazione) - durante lo sviluppo userò principalmente la modalità Reimposta, ma la modalità Unisci dovrebbe funzionare anche a meno che tu non ha apportato modifiche manuali nella stessa configurazione in parallelo

Nota: se si desidera utilizzare solo config_sync per accelerare l'importazione della configurazione durante lo sviluppo del modulo (e non si desidera integrarsi con gli aggiornamenti del client), è sufficiente che questa suite sia installata e abilitata solo nel proprio ambiente (di sviluppo) locale ( supponendo che il tuo modulo andrà in ambienti superiori dopo la finalizzazione e utilizzerai la gestione della configurazione del core D8 per pubblicare la sua configurazione in ambienti superiori).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.