Bagaimana cara memperbarui konfigurasi modul?

33

Saya sedang membangun modul khusus di Drupal 8. Ini mencakup beberapa file konfigurasi YAML.

Ketika saya mengembangkan saya perlu mengubah dan menambahkan ke konfigurasi, misalnya untuk menambah bidang lain ke entitas kustom saya.

Saat ini satu-satunya cara yang saya temukan untuk membuat Drupal memperhatikan perubahannya adalah mencopot modul dan menginstalnya kembali.

Apakah ada cara untuk mendapatkan Drupal untuk memeriksa apakah file konfigurasi yang disediakan oleh modul sama dengan konfigurasi aktif, dan jika tidak, perbarui konfigurasi aktif? Bagaimana pembaruan modul ditangani? Di D7 hook_update_Nakan digunakan untuk menambahkan bidang menggunakan PHP, tetapi sepertinya ini harus ditangani oleh CM di D8?

Hal yang saya coba setelah memperbarui file yml di modul:

  1. drush cr, konfigurasi sinkronisasi.

  2. secara manual menyalin semua file konfigurasi yang diperbarui ke sites/default/files/config_XXX/staging/- tetapi ini memberikan kesalahan ini "Konfigurasi bertahap tidak dapat diimpor, karena berasal dari situs yang berbeda dari situs ini. Anda hanya dapat menyinkronkan konfigurasi antara contoh hasil kloning dari situs ini." .

  3. mengimpor file satu per satu secara manual menggunakan pengelola konfigurasi. Ini berfungsi, tetapi jelas harus ada cara yang lebih otomatis.

  4. [EDIT] secara manual menggunakan modul config_update untuk memeriksa perubahan dan 'mengembalikan' ke konfigurasi modul. Sekali lagi, ini manual.

EDIT: Dari Mengelola konfigurasi - lakukan dan tidak boleh dilakukan

TIDAK

Cobalah untuk mengubah konfigurasi aktif di situs Anda dengan mengubah file di direktori config / install modul. Ini TIDAK akan berfungsi karena Drupal hanya akan membaca dari direktori itu ketika modul diinstal.

... tetapi perubahan akan terjadi, kecuali modul terikat pada konfigurasi apa pun yang mereka butuhkan pada rilis pertama mereka, dan mungkin tidak akan pernah memperbarui atau menambah konfigurasi.

Terima kasih sebelumnya.

artfulrobot
sumber
Saya pikir sesuatu yang sangat mirip ditanyakan sebelumnya (tidak dapat menemukannya sekarang), dan saya kira jawabannya adalah konfigurasi default hanya dikonsultasikan pada waktu instalasi, jadi menginstal ulang adalah cara yang harus dilakukan. Tapi jangan mengutip saya :)
Clive
1
'k, tapi bagaimana modul akan diperbarui? Modul diizinkan untuk mendapatkan pembaruan di D8, kan ;-)? Pasti ada cara (a la config_update) bagi modul untuk mengatakan "Drupal! Saya sekarang memerlukan konfigurasi tambahan ini, lihat dan gabungkan saja."
artfulrobot
Manajer Pembaruan Konfigurasi melakukan pekerjaan, tapi saya setuju rasanya harus ada cara asli untuk melakukan ini. Sesuatu di dalam hook_update_Nsaya anggap, tapi saya tidak yakin apa
Clive
2
Wow, saya pikir jawabannya mungkin berakhir dengan "Anda tidak bisa"! Tidak pernah melihat itu datang! Kembali ke hook_update_N. Artikel bagus tentang Drupal 8 untuk situs kecil (dan bagian 2 ). Di D8 "situs memiliki konfigurasinya, bukan modul" .
artfulrobot
Saya ingin menambahkan bahwa kasus penggunaan yang sangat baik untuk ini adalah pengaturan multi-tempat, di mana Anda ingin berbagi potongan besar konfigurasi khusus tetapi tidak semua dan menyebarkan ini. Ini mungkin termasuk modul khusus. Untuk satu situs itu hanya akan menjadi config ekspor / impor, multisite tidak akan sesederhana itu.
Ambidex

Jawaban:

24

Seperti disebutkan dalam pertanyaan awal, dan komentar lanjutan, ada beragam modul contrib dan metode manual untuk mencapai hal ini.

Untuk melakukannya secara otomatis, atau dengan mode khusus, saya pikir hook_update_N() mungkin masih merupakan opsi yang paling layak.

Misalnya, ini adalah contoh dari Head 2 Head untuk memperbarui system.siteuntuk mengatur default_langcode:

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

Anda juga dapat membaca dalam konfigurasi (disarankan hanya untuk menambah konfigurasi baru, tidak perlu memperbarui atau mengganti konfigurasi yang mungkin telah disesuaikan):

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

di mana $pathpath absolut ke my_config.foo.ymlfile.

jhedstrom
sumber
1
Ketika saya mengikuti pendekatan kedua config ditulis ke Drupal tetapi tidak mendapatkan UUID bahkan ketika saya mengekspornya ke direktori config. Ini membawa saya ke masalah di mana saya mencoba ini dengan Tampilan kustom. Halaman Tinjauan umum tampilan mengembalikan kesalahan fatal karena uuid untuk entitas Config tidak tersedia.
Sebastian
9

Ketika saya mendarat di pertanyaan ini juga tetapi tidak benar-benar menemukan jawaban yang tepat untuk situasi saya di sini, saya ingin menambahkan jawaban lain.

Harap dicatat: Anti-pola di depan!

Gunakan kasing

Ketika kami sedang mengembangkan proyek, kami terus-menerus memperbarui lingkungan pengujian / penerimaan kami dengan pembaruan konfigurasi baru. Ambil contoh modul Berita fiksi sederhana, kami ingin menambahkan tipe konten ke modul dan menyebarkannya ke lingkungan penerimaan kami. Setelah ditinjau, kami menyimpulkan ada beberapa bidang yang hilang dan hal-hal terkait konfigurasi lainnya. Karena kita tahu lingkungan penerimaan tidak diperbarui dalam konfigurasi, kami benar-benar hanya ingin memuat ulang seluruh konfigurasi dari modul sambil menambahkan fungsi baru dan tidak terganggu dengan mengimpor setiap .ymlfile yang diubah .

Kami hanya membutuhkan modul config kami ketika kami sedang mengembangkan multisite. Untuk situs tunggal, sebagian besar kami hanya menggunakan konfigurasi situs yang diekspor di mana langkah selanjutnya tidak perlu.

Masukkan kembali konfigurasi sepenuhnya (anti-pola!)

Kami menemukan bahwa menggunakan layanan ConfigInstaller , kami dapat mengimpor kembali konfigurasi lengkap lagi dari modul tertentu.

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

Gunakan dengan hati-hati!

Saya ingin menambahkan bahwa ini akan menimpa konten aktif apa pun yang telah diubah dalam lingkungan. Jadi, hanya gunakan solusi ini ketika Anda yakin aman untuk menimpa konfigurasi aktif. Kami tidak akan pernah menggunakannya pada lingkungan produksi dan hanya akan diterapkan pada pengembangan awal.

Pertama coba solusi @ jhedstrom sebelum Anda mulai mempertimbangkan yang ini.

Ambidex
sumber
9

Saya telah menemukan inti ini di GitHub, yang mengembalikan / memuat ulang konfigurasi modul menggunakan drush:

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

Berdasarkan komentar saya: Bagaimana cara saya memperbarui konfigurasi modul?

Ketika saya mengikuti pendekatan kedua config ditulis ke Drupal tetapi tidak mendapatkan UUID bahkan ketika saya mengekspornya ke direktori config. Ini membawa saya ke masalah di mana saya mencoba ini dengan Tampilan kustom. Halaman Gambaran umum tampilan mengembalikan kesalahan fatal karena uuid untuk entitas Config tidak tersedia.

Saya telah membuat fungsi kecil yang membantu saya, di sini contoh kode saya:

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

Jawaban di atas (re-import penuh) bekerja untuk use case saya juga, tetapi pertama-tama saya menghabiskan sedikit waktu untuk melihat re-import yang lebih selektif. Inilah kode yang saya miliki yang sepertinya berfungsi sebagai kait pembaruan dan didasarkan pada kode di modul 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
sumber
1

Modul Konfigurasi Synchronizer membantu menyelesaikan masalah ini dengan cara yang baik. Modul 7 modul ini tampaknya sedikit berlebihan hanya untuk kasus ini (maksudnya adalah untuk secara aman menggabungkan pembaruan tanpa menimpa kustomisasi), tetapi karena konsepnya itu juga memungkinkan untuk melacak dan mengimpor perubahan konfigurasi dari modul / instal dan / folder opsional dengan cepat.

Pada dasarnya, Anda dapat mengujinya seperti berikut:

  • buat dan aktifkan modul khusus Anda di lingkungan lokal Anda dengan beberapa item konfigurasi "default" ditempatkan di / config / instal folder seperti biasa
  • instal dan aktifkan modul config_sync dan semua modul yang bergantung padanya
  • lakukan beberapa pengeditan di item konfigurasi modul Anda di dalam folder / config / install
  • akses / admin / config / pengembangan / konfigurasi / distro. Anda akan melihat perubahan Anda dan memiliki opsi untuk mengimpornya ke konfigurasi aktif (mode Gabung dimaksudkan untuk mempertahankan perubahan klien, Reset mode memaksa impor) - selama pengembangan saya sebagian besar akan menggunakan mode Reset, tetapi mode menggabungkan harus bekerja juga kecuali Anda melakukan perubahan manual dalam konfigurasi yang sama secara paralel

Catatan: jika Anda hanya ingin menggunakan config_sync untuk mempercepat impor konfigurasi selama pengembangan modul (dan Anda tidak peduli tentang penggabungan dengan pembaruan klien), itu cukup untuk memiliki suite ini diinstal dan diaktifkan pada lingkungan (pengembangan) lokal Anda saja ( dengan asumsi modul Anda akan pergi ke lingkungan yang lebih tinggi setelah menyelesaikan dan Anda menggunakan manajemen konfigurasi inti D8 untuk memposting konfigurasinya ke lingkungan yang lebih tinggi).

Mirsoft
sumber