Drupal 8.でカスタムモジュールを構築しています。これには、いくつかのYAML構成ファイルが含まれています。
開発中は、変更して構成に追加する必要があります。カスタムエンティティに別のフィールドを追加します。
現在、Drupalを取得するために変更を確認する唯一の方法は、モジュールをアンインストールして再インストールすることです。
Drupalを取得して、モジュールによって提供される構成ファイルがアクティブな構成と同じであることを確認し、異なる場合はアクティブな構成を更新する方法はありますか?モジュールの更新はどのように処理されますか? hook_update_N
は、PHPを使用してフィールドを追加するために使用されますが、これはD8のCMで処理する必要があるようです。
モジュールのymlファイルを更新した後に私が試したこと:
drush cr
、構成の同期。
更新されたすべての構成ファイルを手動でsites/default/files/config_XXX/staging/
にコピーします-しかし、これによりこのエラーが発生します "ステージングされた構成は、このサイトとは異なるサイトからのものであるためインポートできません。構成の同期のみが可能ですこのサイトの複製されたインスタンス間。」.
構成マネージャーを使用してファイルを1つずつ手動でインポートする。これは機能しますが、明らかにより自動化された方法が必要です。
[編集]手動で config_update モジュールを使用して変更を検査し、モジュールの構成に「戻す」。これも手動です。
EDIT:From Managing configuration-do's and don'ts
DON'TS
モジュールのconfig/installディレクトリのファイルを変更して、サイトのアクティブな構成を変更してみてください。 Drupalは、モジュールのインストール時にそのディレクトリからのみ読み取るため、これは機能しません。
...しかし、変更が発生します。ただし、モジュールが最初のリリースで必要な構成にバインドされておらず、構成を更新または追加することはできません。
前もって感謝します。
元の質問とフォローアップコメントで述べたように、これを達成するためのさまざまな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));
ここで、$path
はmy_config.foo.yml
ファイルへの絶対パスです。
私はGitHubで this Gist を見つけました。これは、drushを使用して、指定されたモジュールの構成を元に戻す/リロードします。
drush cim -y --partial --source=modules/path/to/module/config/install/
私もこの質問にたどり着きましたが、ここで私の状況に対する正しい答えが本当に見つからなかったので、別の答えを追加したいと思います。
プロジェクトを開発しているときは、新しい構成の更新でテスト/受け入れ環境を常に更新しています。簡単な架空のニュースモジュールを例にとると、コンテンツタイプをモジュールに追加し、これを受け入れ環境にデプロイします。レビューの結果、いくつかのフィールドが欠落していること、およびその他の構成関連の要素があることがわかりました。アクセプタンス環境が構成で更新されていないことがわかっているため、新しい機能を追加しながらモジュールから構成全体をリロードし、変更されたすべての.yml
ファイル。
マルチサイトを開発しているときは、モジュールの構成だけが必要です。単一サイトの場合、ほとんどの場合、次の手順が不要なエクスポートされたサイト構成のみを使用します。
ConfigInstaller サービスを使用すると、特定のモジュールから完全な構成を再度インポートできることがわかりました。
// Implement in a update_N hook.
\Drupal::service('config.installer')->installDefaultConfig('module', $module);
これにより、環境内で変更されたアクティブコンテンツが上書きされることを付け加えておきます。したがって、アクティブな構成を上書きしても安全であると確信できる場合にのみ、このソリューションを使用してください。これを本番環境で使用することは決してなく、初期の開発にのみ適用されます。
これを検討する前に、まず@jhedstromのソリューションを試してください。
私のコメントに基づいて: モジュールの構成を更新するにはどうすればよいですか?
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.';
}
上記の答え(完全な再インポート)も私のユースケースで機能しましたが、最初に、より選択的な再インポートを検討する間、少し時間を費やしました。以下は、更新フックとして機能しているように見え、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,
];
}
Configuration Synchronizer モジュールは、この問題を適切に解決するのに役立ちます。この7つのモジュールのモジュールスイートは、この場合だけは少しやり過ぎに見えるようです(主に、カスタマイズを上書きせずに更新を安全にマージすることを目的としています)。その概念により、モジュールの/ installから構成の変更を追跡およびインポートすることもできます。/optionalフォルダー。
基本的には、次のようにテストできます。
注:onlyモジュールの開発中にconfig_syncを使用して構成のインポートを高速化したい場合(そしてクライアントの更新とのマージを気にしない場合)、このスイートをローカル(開発)環境にのみインストールして有効にするだけで十分です(モジュールがファイナライズ後に上位環境に移動し、D8コア構成管理を使用して構成を上位環境にポストするとします)。