web-dev-qa-db-ja.com

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

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

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

現在、Drupalを取得するために変更を確認する唯一の方法は、モジュールをアンインストールして再インストールすることです。

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

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

  1. drush cr、構成の同期。

  2. 更新されたすべての構成ファイルを手動でsites/default/files/config_XXX/staging/にコピーします-しかし、これによりこのエラーが発生します "ステージングされた構成は、このサイトとは異なるサイトからのものであるためインポートできません。構成の同期のみが可能ですこのサイトの複製されたインスタンス間。」.

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

  4. [編集]手動で config_update モジュールを使用して変更を検査し、モジュールの構成に「戻す」。これも手動です。

EDIT:From Managing configuration-do's and don'ts

DON'TS

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

...しかし、変更が発生します。ただし、モジュールが最初のリリースで必要な構成にバインドされておらず、構成を更新または追加することはできません。

前もって感謝します。

32
artfulrobot

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

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

たとえば、これはsystem.siteを更新してdefault_langcodeを設定する Head 2 Head の例です。

  $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));

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

24
jhedstrom

私はGitHubで this Gist を見つけました。これは、drushを使用して、指定されたモジュールの構成を元に戻す/リロードします。

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

私もこの質問にたどり着きましたが、ここで私の状況に対する正しい答えが本当に見つからなかったので、別の答えを追加したいと思います。

注意:アンチパターンが先です!

使用事例

プロジェクトを開発しているときは、新しい構成の更新でテスト/受け入れ環境を常に更新しています。簡単な架空のニュースモジュールを例にとると、コンテンツタイプをモジュールに追加し、これを受け入れ環境にデプロイします。レビューの結果、いくつかのフィールドが欠落していること、およびその他の構成関連の要素があることがわかりました。アクセプタンス環境が構成で更新されていないことがわかっているため、新しい機能を追加しながらモジュールから構成全体をリロードし、変更されたすべての.ymlファイル。

マルチサイトを開発しているときは、モジュールの構成だけが必要です。単一サイトの場合、ほとんどの場合、次の手順が不要なエクスポートされたサイト構成のみを使用します。

設定を完全に再インポートする(アンチパターン!)

ConfigInstaller サービスを使用すると、特定のモジュールから完全な構成を再度インポートできることがわかりました。

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

注意して使用してください!

これにより、環境内で変更されたアクティブコンテンツが上書きされることを付け加えておきます。したがって、アクティブな構成を上書きしても安全であると確信できる場合にのみ、このソリューションを使用してください。これを本番環境で使用することは決してなく、初期の開発にのみ適用されます。

これを検討する前に、まず@jhedstromのソリューションを試してください。

10
Ambidex

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

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

私はそれを助ける小さな関数を作成しました、ここに私のサンプルコード:

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.';
}
2
Sebastian

上記の答え(完全な再インポート)も私のユースケースで機能しましたが、最初に、より選択的な再インポートを検討する間、少し時間を費やしました。以下は、更新フックとして機能しているように見え、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
pwolanin

Configuration Synchronizer モジュールは、この問題を適切に解決するのに役立ちます。この7つのモジュールのモジュールスイートは、この場合だけは少しやり過ぎに見えるようです(主に、カスタマイズを上書きせずに更新を安全にマージすることを目的としています)。その概念により、モジュールの/ installから構成の変更を追跡およびインポートすることもできます。/optionalフォルダー。

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

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

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

1
Mirsoft