Как мне обновить конфигурацию модуля?


33

Я создаю пользовательский модуль в Drupal 8. Он включает в себя некоторые файлы конфигурации YAML.

По мере разработки мне нужно изменить и добавить в конфигурацию, например, добавить еще одно поле в мой пользовательский объект.

В настоящее время единственный способ заставить Drupal заметить изменения - это удалить модуль и переустановить его.

Есть ли способ заставить Drupal проверить, что файлы конфигурации, предоставляемые модулями, совпадают с активной конфигурацией, и если нет, обновить активную конфигурацию? Как обрабатываются обновления модуля? В D7 hook_update_Nбудет использоваться для добавления полей с использованием PHP, но, похоже, это должно быть обработано CM в D8?

Вещи, которые я пробовал после обновления файлов yml в модуле:

  1. drush crКонфигурация синхронизации.

  2. вручную скопируйте все обновленные файлы конфигурации в файл, sites/default/files/config_XXX/staging/но это приводит к этой ошибке: «Этапная конфигурация не может быть импортирована, поскольку она создается с сайта, отличного от этого сайта. Вы можете синхронизировать конфигурацию только между клонированными экземплярами этого сайта». ,

  3. вручную импортируйте файлы по одному с помощью менеджера конфигурации. Это работает, но, очевидно, должен быть более автоматический путь.

  4. [EDIT] вручную использует модуль config_update для проверки изменений и «возврата» к конфигурации модуля. Опять же, это руководство.

РЕДАКТИРОВАТЬ: Из управления конфигурацией - делать и не делать

НЕЛЬЗЯ

Попробуйте изменить активную конфигурацию на вашем сайте, изменив файлы в каталоге config / install модуля. Это НЕ будет работать, потому что Drupal будет читать только из этого каталога, когда модуль установлен.

... но изменения там собираются произойти, если модули не связаны с любой конфиг они нуждались в их первый когда - либо отпустить, и никогда не может когда - либо обновления или добавления конфигурации.

Заранее спасибо.


Я думаю, что что-то очень похожее было задано ранее (не могу найти его сейчас), и я думаю, что ответ был таков, что с конфигурацией по умолчанию обращаются только во время установки, поэтому переустановка - это путь. Не цитируйте меня, хотя :)
Клайв

1
'k, но как модуль будет обновлен? Модули могут получать обновления в D8, верно ;-)? У модулей должен быть способ (в виде config_update) сказать: «Drupal! Теперь мне нужна эта дополнительная конфигурация, посмотрите и объедините ее, пожалуйста».
artfulrobot

Диспетчер обновлений конфигурации выполняет эту работу, но я согласен с тем, что для этого должен быть собственный способ. Что-то в этом hook_update_Nя бы предположил, но я не уверен, что
Клайв

2
Ух ты, я думаю, что ответ может быть "ты не можешь"! Никогда не ожидал этого! Вернуться к hook_update_N. Отличная статья о Drupal 8 для небольших сайтовчасть 2 ). В D8 «сайты имеют свою конфигурацию, а не модули» .
artfulrobot

Я хотел бы добавить, что отличным вариантом использования для этого является многосайтовая установка, где вы хотели бы поделиться определенными большими частями конфигурации, но не всеми, и развернуть это. Они могут включать пользовательские модули. Для одного сайта это будет просто экспорт / импорт конфигурации, а для нескольких сайтов это будет не так просто.
Ambidex

Ответы:


24

Как уже упоминалось в первоначальном вопросе и последующих комментариях, для достижения этой цели существует множество модулей contrib и ручных методов.

Делать это автоматически или по hook_update_N()своему усмотрению , я думаю, по-прежнему, вероятно, самый жизнеспособный вариант.

Например, это пример из Head 2 Head для обновления, system.siteчтобы установить default_langcode:

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

Вы также можете прочитать в конфигурации (рекомендуется только для добавления новой конфигурации, не обязательно обновления или переопределения конфигурации, которая могла быть настроена):

  $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абсолютный путь к my_config.foo.ymlфайлу.


1
Когда я следую второму подходу, конфигурация записывается в Drupal, но не получает UUID, даже когда я экспортирую его в каталог config. Это привело меня к проблеме, где я попробовал это с пользовательским представлением. Страница обзора Views вернула мне фатальную ошибку, так как uuid для сущности Config был недоступен.
Себастьян

9

Поскольку я тоже нашел этот вопрос, но не нашел здесь правильного ответа для своей ситуации, я хотел бы добавить еще один ответ.

Обратите внимание: анти-паттерн впереди!

Случай использования

Когда мы разрабатываем проекты, мы постоянно обновляем нашу среду тестирования / принятия новыми обновлениями конфигурации. Возьмем, к примеру, простой вымышленный модуль новостей, мы хотели бы добавить тип контента в модуль и развернуть его в нашей среде принятия. После проверки мы пришли к выводу, что пропало несколько полей и другие вещи, связанные с конфигурацией. Поскольку мы знаем, что среда принятия не обновляется в конфигурации, мы действительно хотим перезагрузить всю конфигурацию из модуля, в то время как добавлены новые функциональные возможности, и не беспокоиться об импорте каждого измененного .ymlфайла.

Нам нужен только наш конфиг в модулях, когда мы разрабатываем мультисайты. Для отдельных сайтов мы в основном просто используем экспортированную конфигурацию сайта, в которой следующий шаг не нужен.

Повторно импортируйте конфигурацию полностью (анти-шаблон!)

Мы обнаружили, что с помощью службы ConfigInstaller мы можем снова импортировать полную конфигурацию из определенного модуля.

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

Используйте с осторожностью!

Я хотел бы добавить, что это перезапишет любой активный контент, который был изменен в среде. Поэтому используйте это решение только тогда, когда вы уверены, что можно перезаписать активную конфигурацию. Мы никогда не будем использовать это в производственной среде и будем применять только на ранних этапах разработки.

Сначала попробуйте решение @ jhedstrom, прежде чем приступить к рассмотрению этого.


9

Я нашел этот Gist на GitHub, который возвращает / перезагружает данную конфигурацию модуля, используя drush:

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

2

На основании моего комментария: Как мне обновить конфигурацию модуля?

Когда я следую второму подходу, конфигурация записывается в Drupal, но не получает UUID, даже когда я экспортирую его в каталог config. Это привело меня к проблеме, где я попробовал это с пользовательским представлением. Страница обзора Views вернула мне фатальную ошибку, так как uuid для сущности Config был недоступен.

Я создал небольшую функцию, которая помогает мне в этом, вот мой пример кода:

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

Ответ выше (полный повторный импорт) работал и для моего варианта использования, но сначала я потратил немного времени на поиск более избирательного повторного импорта. Вот код, который у меня был, который, казалось, работал как хук обновления и был основан на коде в модуле 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

Модуль Synchronizer конфигурации помогает решить эту проблему хорошим способом. Этот набор модулей из 7 модулей кажется немного излишним только для этого случая (его целью является в основном безопасное объединение обновлений без перезаписи настроек), но благодаря своей концепции он также позволяет отслеживать и импортировать изменения конфигурации из модуля / установки и / дополнительные папки быстро.

По сути, вы можете проверить это следующим образом:

  • создайте и включите свой пользовательский модуль в локальной среде, используя некоторые элементы конфигурации «по умолчанию», как обычно, в папке / config / install
  • установить и включить модуль config_sync и все его зависимые модули
  • внесите некоторые изменения в элемент конфигурации вашего модуля в папке / config / install
  • доступ / admin / config / development / configuration / distro. Вы должны увидеть ваши изменения и иметь возможность импортировать их в активную конфигурацию (режим слияния предназначен для сохранения изменений клиента, режим сброса форсирует импорт) - во время разработки я в основном буду использовать режим сброса, но режим слияния должен работать, если только вы делали какие-либо ручные изменения в той же конфигурации параллельно

Примечание: если вы только хотите использовать config_sync для ускорения импорта конфигурации в процессе разработки модуля (и вы не заботитесь о слиянии с использованием клиентских обновлений), этого достаточно , чтобы установил этот набор и доступен только на локальные (развитие) средах ( при условии, что ваш модуль перейдет в более высокие среды после завершения, и вы используете управление конфигурацией ядра D8 для публикации его конфигурации в более высоких средах).

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.