Як оновити конфігурацію модуля?


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 для перевірки змін та «повернення» до конфігурації модуля. Знову ж таки, це посібник.

EDIT: З керування конфігурацією - робити і не робити

НЕ ДЛЯ

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

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

Заздалегідь спасибі.


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

1
'k, але як би модуль оновлювався? Модулі дозволяють отримувати оновлення в D8, правда ;-)? Повинен бути спосіб (a la config_update) сказати модулі "Drupal! Мені зараз потрібна додаткова конфігурація, погляньте і з’єднайте її, будь ласка".
artfulrobot

Менеджер оновлень конфігурації виконує цю роботу, але я погоджуюсь, здається, що для цього має бути рідний спосіб. Щось у цьому hook_update_Nя припускаю, але я не впевнений у чому
Клайв

2
Нічого собі, я думаю, що відповідь може закінчитися "ти не можеш"! Ніколи не бачив, щоб це прийшло! Повернутися до hook_update_N. Відмінна стаття про Drupal 8 для невеликих сайтів (та частина 2 ). У D8 "сайти мають свою конфігурацію, а не модулі" .
artfulrobot

Я хотів би додати, що відмінним випадком використання для цього є багатосайтове налаштування, де ви хочете поділитися конкретними великими фрагментами конфігурації, але не всіми та розгорнути це. Вони можуть включати спеціальні модулі. Для одного сайту це був би просто експорт / імпорт конфігурації, багатомісний сайт був би не таким простим.
Ambidex

Відповіді:


24

Як уже згадувалося в первинному запитанні та коментарях, що надаються, існують різноманітні модулі, що надають внески, та ручні методи для цього.

Зробити це автоматично або на замовлення, я думаю, що hook_update_N()це все-таки найбільш життєздатний варіант.

Наприклад, це приклад оновлення голови 2system.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();

Ви також можете читати в config (рекомендується лише для додавання нового конфігурації, не обов'язково оновлюючи або переосмислюючи конфігурацію, яка може бути налаштована):

  $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. Це спричинило мене до проблеми, коли я спробував це зі спеціальним представленням. Сторінка огляду переглядів повернула мені фатальну помилку, оскільки uuid для об'єкта Config був недоступний.
Себастьян

9

Коли я приземлився і на це питання, але насправді не знайшов правильної відповіді для своєї ситуації тут, я хотів би додати ще одну відповідь.

Зверніть увагу: Анти-візерунок попереду!

Використовуйте футляр

Коли ми розробляємо проекти, ми постійно оновлюємо тестове / приймальне середовище новими оновленнями конфігурації. Візьмемо для прикладу простий вигаданий модуль News, ми хотіли б додати тип вмісту до модуля та розгорнути це у нашому середовищі прийняття. Після огляду ми дійшли висновку, що є кілька полів, відсутніх та інших матеріалів, пов’язаних з конфігурацією. Оскільки ми знаємо, що середовище прийняття не оновлюється в config, ми дійсно хочемо лише перезавантажити всю конфігурацію з модуля, додавши нову функціональність, і не турбуватись імпортом кожного зміненого .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. Це спричинило мене до проблеми, коли я спробував це зі спеціальним представленням. Сторінка огляду переглядів повернула мені фатальну помилку, оскільки 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

Модуль синхронізації конфігурації допомагає вирішити цю проблему приємним чином. Цей набір модулів із 7 модулів здається трохи надмірним для цього випадку (його намір полягає в безпечному об'єднанні в оновлення без перезавантаження налаштувань), але завдяки своїй концепції він також дозволяє відстежувати та імпортувати зміни конфігурації з модуля / встановлення та / Необов’язкові папки швидко.

В основному, ви можете перевірити його так:

  • створити та включити свій власний модуль у вашому локальному середовищі, коли деякі елементи конфігурації за замовчуванням розміщуються в папці / config / install як зазвичай
  • встановити та включити модуль config_sync та всі його залежні модулі
  • виконати кілька змін у конфігураційному елементі модуля всередині папки / config / install
  • доступ / адміністратор / конфігурація / розробка / конфігурація / дистрибутив. Ви повинні побачити свою зміну та мати можливість імпортувати її в активну конфігурацію (режим об'єднання призначений для збереження змін клієнта; режим скидання змушує імпортувати) - під час розробки я буду використовувати переважно режим скидання, але режим злиття повинен працювати так само, якщо ви не робив паралельно будь-які зміни вручну в одній конфігурації вручну

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.