モジュールの構成を更新するにはどうすればよいですか?


33

Drupal 8でカスタムモジュールを作成しています。これには、いくつかのYAML構成ファイルが含まれています。

開発中に、たとえばカスタムエンティティに別のフィールドを追加するなど、構成を変更して追加する必要があります。

現在、Drupalに変更を通知する唯一の方法は、モジュールをアンインストールしてから再インストールすることです。

モジュールが提供する構成ファイルがアクティブな構成と同じであることをDrupalに確認させ、そうでない場合はアクティブな構成を更新する方法はありますか?モジュールの更新はどのように処理されますか?D7 hook_update_Nでは、PHPを使用してフィールドを追加するために使用されますが、これはD8のCMで処理されるように見えますか?

モジュールのymlファイルを更新した後に試したこと:

  1. drush cr、設定の同期。

  2. 更新されたすべての構成ファイルを手動でコピーしますsites/default/files/config_XXX/staging/-ただし、このエラーは「ステージングされた構成はこのサイトとは異なるサイトから作成されたためインポートできません。このサイトのクローンインスタンス間でのみ構成を同期できます」

  3. 構成マネージャーを使用してファイルを1つずつ手動でインポートします。これは機能しますが、明らかにもっと自動化された方法が必要です。

  4. [編集] config_updateモジュールを手動で使用して、変更を検査し、モジュールの構成に「元に戻す」。繰り返しますが、これはマニュアルです。

編集:設定の管理から-すべきこととしないこと

禁止事項

モジュールのconfig / installディレクトリのファイルを変更して、サイトのアクティブな構成を変更してください。Drupalはモジュールのインストール時にそのディレクトリからのみ読み取るため、これは機能しません。

...しかし、変更があるだろうモジュールが、彼らは彼らの初のリリースに必要な設定ファイル、およびこれまでに更新していないか、設定を追加しないことが何にバインドされていない限り、発生します。

前もって感謝します。


非常によく似たものが以前に尋ねられたと思います(今はそれを見つけることができません)、そして答えはデフォルト設定はインストール時にのみ参照されるので、再インストールが進むべき方法だと思います。私を引用しないでください:)
クライブ

1
'k、しかしモジュールはどのように更新されますか?モジュールはD8で更新を取得できます;-)?モジュールに「Drupal!この追加の構成が必要になったので、見て、それをマージしてください」と言う方法(config_update)が必要です。
artfulrobot

Configuration Update Managerがジョブを実行しますが、ネイティブな方法でこれを行う必要があると感じています。hook_update_N私は何かを推測しますが、私は何がわからない
クライブ

2
うわー、答えは「できない」になってしまうかもしれないと思います!それが来るのを見たことがない!に戻るhook_update_N小規模サイト向けのDrupal 8に関する優れた記事(およびパート2)。D8 では、「サイトはモジュールではなく構成を所有します」
artfulrobot

これの優れたユースケースはマルチサイト設定であり、すべてではなく特定の構成の大部分を共有して展開することです。これらにはカスタムモジュールが含まれる場合があります。単一のサイトの場合、構成のエクスポート/インポートだけで、マルチサイトはそれほど単純ではありません。
アンビデックス

回答:


24

元の質問とフォローアップコメントで述べたように、これを達成するためのさまざまなcontribモジュールと手動の方法があります。

自動的に、またはカスタムの方法でそれを行うには、hook_update_N()おそらく最も実行可能なオプションだと思います。

たとえば、これは更新するHead 2 Headの例です:system.sitedefault_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));

ここで$pathmy_config.foo.ymlファイルへの絶対パスです。


1
2番目のアプローチに従うと、構成はDrupalに書き込まれますが、構成ディレクトリにエクスポートしてもUUIDを取得しません。これは、カスタムビューでこれを試した問題に私を導きました。Configエンティティのuuidが利用できなかったため、Views概要ページから致命的なエラーが返されました。
セバスチャン

9

私もこの質問に着手しましたが、ここで自分の状況に対する正しい答えを見つけられなかったので、別の答えを追加したいと思います。

注意:アンチパターンを先に!

使用事例

プロジェクトを開発しているときは、新しい構成の更新でテスト/受け入れ環境を常に更新しています。たとえば、単純な架空のニュースモジュールを取り上げます。コンテンツタイプをモジュールに追加し、これを受け入れ環境にデプロイします。確認後、不足しているフィールドやその他の構成関連のものがいくつかあると判断しました。受け入れ環境がconfigで更新されていないことがわかっているので、実際にはモジュールから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

コメントに基づいて:モジュールの構成を更新するにはどうすればよいですか?

2番目のアプローチに従うと、構成はDrupalに書き込まれますが、構成ディレクトリにエクスポートしてもUUIDを取得しません。これは、カスタムビューでこれを試した問題に私を導きました。Configエンティティのuuidが利用できなかったため、Views概要ページから致命的なエラーが返されました。

これを支援する小さな関数を作成しました。ここに私のサンプルコードを示します。

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つのモジュールのモジュールスイートは、この場合だけでは少しやり過ぎだと思われます(主にカスタマイズを上書きせずに更新を安全にマージすることを目的としています)が、その概念のために、モジュールの/ installからの構成変更を追跡およびインポートすることもできます/ optionalフォルダー。

基本的に、次のようにテストできます。

  • 通常のように/ config / installフォルダーに配置されたいくつかの「デフォルト」構成アイテムを使用して、ローカル環境でカスタムモジュールを作成して有効にします。
  • config_syncモジュールとそのすべての依存モジュールをインストールして有効にします
  • / config / installフォルダー内のモジュールの構成アイテムを編集します。
  • / admin / config / development / configuration / distroにアクセスします。変更が表示され、アクティブな構成にインポートするオプションがあります(マージモードはクライアントの変更を保持することを目的とし、リセットモードはインポートを強制します)-開発中は主にリセットモードを使用しますが、マージモードも同様に機能します同じ設定で手動で変更を並行して行った

注:config_sync のみを使用してモジュールの開発中に構成のインポートを加速する場合(およびクライアントの更新とのマージを気にしない場合)、このスイートをローカル(開発)環境のみにインストールして有効にすれば十分です(ファイナライズ後にモジュールがより高い環境に移動すると想定し、D8コア構成管理を使用して、その構成をより高い環境にポストします)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.