¿Cómo actualizo la configuración de un módulo?

33

Estoy creando un módulo personalizado en Drupal 8. Incluye algunos archivos de configuración YAML.

A medida que me desarrolle, necesito cambiar y agregar a la configuración, por ejemplo, agregar otro campo a mi entidad personalizada.

En la actualidad, la única forma en que he encontrado que Drupal nota los cambios es desinstalar el módulo y volver a instalarlo.

¿Hay alguna manera de hacer que Drupal verifique que los archivos de configuración proporcionados por los módulos sean los mismos que los de la configuración activa y, si no, actualice la configuración activa? ¿Cómo se manejan las actualizaciones del módulo? En D7 hook_update_Nse usaría para agregar campos usando PHP, pero parece que esto debería ser manejado por el CM en D8.

Cosas que he probado después de actualizar los archivos yml en el módulo:

  1. drush cr, sincronización de configuración.

  2. copiando manualmente todos los archivos de configuración actualizados sites/default/files/config_XXX/staging/, pero esto genera este error "La configuración por etapas no se puede importar, porque se origina en un sitio diferente a este sitio. Solo puede sincronizar la configuración entre instancias clonadas de este sitio". .

  3. Importar manualmente los archivos uno por uno utilizando el administrador de configuración. Esto funciona, pero obviamente debe haber una forma más automática.

  4. [EDITAR] use manualmente el módulo config_update para inspeccionar los cambios y 'revertir' a la configuración del módulo. De nuevo, esto es manual.

EDITAR: desde la configuración de gestión - qué hacer y qué no hacer

NO HACER

Intente cambiar la configuración activa en su sitio cambiando los archivos en el directorio config / install de un módulo. Esto NO funcionará porque Drupal solo leerá desde ese directorio cuando el módulo esté instalado.

... pero los cambios van a suceder, a menos que los módulos estén vinculados a cualquier configuración que necesiten en su primer lanzamiento, y nunca puedan actualizar o agregar configuraciones.

Gracias por adelantado.

artfulrobot
fuente
Creo que se preguntó algo muy similar antes (no puedo encontrarlo ahora), y creo que la respuesta fue que la configuración predeterminada solo se consulta en el momento de la instalación, por lo que la reinstalación es el camino a seguir. Aunque no me cites :)
Clive
1
'k, pero ¿cómo se actualizaría un módulo? Los módulos pueden obtener actualizaciones en D8, ¿verdad ;-)? Debe haber una forma (a la config_update) para que los módulos digan "¡Drupal! Ahora necesito esta configuración adicional, eche un vistazo y combínela por favor".
artfulrobot
Configuration Update Manager hace el trabajo, pero estoy de acuerdo en que parece que debería haber una forma nativa de hacerlo. Asumiría algo hook_update_N, pero no estoy seguro de qué
Clive
2
¡Vaya, creo que la respuesta podría terminar siendo "no puedes"! ¡Nunca lo vi venir! De vuelta a hook_update_N. Excelente artículo sobre Drupal 8 para sitios pequeños (y parte 2 ). En D8 "los sitios poseen su configuración, no los módulos" .
artfulrobot
Me gustaría agregar que un excelente caso de uso para esto es una configuración multisitio, donde le gustaría compartir grandes piezas específicas de configuración pero no todas e implementar esto. Estos pueden incluir módulos personalizados. Para un solo sitio, sería simplemente una exportación / importación de configuración, un sitio múltiple no sería tan simple.
Ambidex

Respuestas:

24

Como se mencionó en la pregunta original y en los comentarios de seguimiento, hay una variedad de módulos contrib y métodos manuales para lograr esto.

Para hacerlo automáticamente, o de manera personalizada, creo hook_update_N() todavía es probablemente la opción más viable.

Por ejemplo, este es un ejemplo de Head 2 Head para actualizar system.sitey configurar default_langcode:

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

También puede leer en la configuración (recomendado solo para agregar una nueva configuración, no necesariamente actualizar o anular la configuración que puede haber sido personalizada):

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

donde $pathes la ruta absoluta al my_config.foo.ymlarchivo.

jhedstrom
fuente
1
Cuando sigo el segundo enfoque, la configuración se escribe en Drupal pero no obtiene un UUID incluso cuando lo exporto al directorio de configuración. Esto me llevó a un problema en el que probé esto con una vista personalizada. La página de vista general de Vistas me devolvió un error grave ya que el uuid para la entidad Config no estaba disponible.
Sebastián
9

Cuando llegué a esta pregunta también pero realmente no encontré la respuesta correcta para mi situación aquí, me gustaría agregar otra respuesta.

Tenga en cuenta: ¡Anti-patrón por delante!

Caso de uso

Cuando desarrollamos proyectos, actualizamos constantemente nuestro entorno de prueba / aceptación con nuevas actualizaciones de configuración. Tomemos, por ejemplo, un simple módulo de noticias ficticio, nos gustaría agregar un tipo de contenido al módulo e implementarlo en nuestro entorno de aceptación. Después de la revisión, hemos concluido que faltan algunos campos y otras cosas relacionadas con la configuración. Dado que sabemos que el entorno de aceptación no se está actualizando en la configuración, realmente solo queremos volver a cargar toda la configuración desde el módulo mientras se agrega una nueva funcionalidad y no molestarnos al importar cada .ymlarchivo modificado .

Solo necesitamos nuestra configuración en los módulos cuando estamos desarrollando sitios múltiples. Para sitios individuales, en su mayoría solo usamos la configuración de sitio exportada en la que el siguiente paso es innecesario.

Reimportar la configuración por completo (¡antipatrón!)

Descubrimos que al usar el servicio ConfigInstaller , podemos volver a importar la configuración completa desde un módulo específico.

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

Usar con precaución!

Me gustaría agregar que esto sobrescribirá cualquier contenido activo que haya sido alterado dentro del entorno. Por lo tanto, solo use esta solución cuando esté seguro de que es seguro sobrescribir la configuración activa. Nunca usaremos esto en un entorno de producción y solo aplicaremos en el desarrollo temprano.

Primero pruebe la solución de @ jhedstrom antes de comenzar a considerar esta.

Ambidex
fuente
9

He encontrado este Gist en GitHub, que revierte / recarga la configuración del módulo dada usando drush:

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

Basado en mi comentario: ¿Cómo actualizo la configuración de un módulo?

Cuando sigo el segundo enfoque, la configuración se escribe en Drupal pero no obtiene un UUID incluso cuando lo exporto al directorio de configuración. Esto me llevó a un problema en el que probé esto con una vista personalizada. La página de vista general de Vistas me devolvió un error grave ya que el uuid para la entidad Config no estaba disponible.

He creado una pequeña función que me ayuda con eso, aquí mi código de ejemplo:

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
fuente
1

La respuesta anterior (reimportación completa) también funcionó para mi caso de uso, pero primero pasé un tiempo buscando una reimportación más selectiva. Aquí está el código que tenía que parecía funcionar como un enlace de actualización y estaba basado en el código del módulo 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
fuente
1

Sincronizador de configuración módulo ayuda a resolver este problema de una manera agradable. Este conjunto de módulos de 7 módulos parece ser un poco exagerado solo para este caso (su intención es principalmente fusionar de manera segura las actualizaciones sin sobrescribir las personalizaciones), pero debido a su concepto también permite rastrear e importar cambios de configuración desde el módulo / instalación y / carpetas opcionales rápidamente.

Básicamente, puede probarlo de la siguiente manera:

  • cree y habilite su módulo personalizado en su entorno local con algunos elementos de configuración "predeterminados" ubicados en la carpeta / config / install como de costumbre
  • instalar y habilitar el módulo config_sync y todos sus módulos dependientes
  • haga algunas ediciones en el elemento de configuración de su módulo dentro de la carpeta / config / install
  • acceso / admin / config / desarrollo / configuración / distro. Debería ver su cambio y tener la opción de importarlo a la configuración activa (el modo de fusión está destinado a preservar los cambios del cliente, el modo de reinicio fuerza la importación): durante el desarrollo utilizaré principalmente el modo de reinicio, pero el modo de fusión debería funcionar también a menos que usted hizo algún cambio manual en la misma configuración en paralelo

Nota: si solo desea usar config_sync para acelerar la importación de la configuración durante el desarrollo del módulo (y no le importa fusionarse con las actualizaciones del cliente), es suficiente tener esta suite instalada y habilitada solo en su entorno local (desarrollo) ( suponiendo que su módulo irá a entornos superiores después de finalizar y utilizar la administración de configuración central D8 para publicar su configuración en entornos superiores).

Mirsoft
fuente