Drupal 8(A and B)、(A)に2つの同一サイトがあります。カスタムブロックを作成し(ブロック/追加)、構成をエクスポートします(drush config-export)この構成を(B)にインポートします(drush config-import)、エラーはありませんが、サイト(B)でインポートしたブロックは、「このブロックが壊れているか、欠落しています。コンテンツが欠落している可能性があります。または、元のモジュールを有効にする必要があるかもしれません。」そして、このブロックのコンテンツを編集できません。どうすれば修正できますか?
サイトA:
サイトB:
サイトAからすべてのカスタムブロックデータをエクスポートしてサイトBにインポートするためのすばやくダーティな方法を探している人のために(重要:これにより、サイトBのカスタムブロックコンテンツが上書きされます):
サイトA:
移行データを入れるディレクトリを作成します。
mkdir block_migration
ブロック固有のテーブルを個々のファイルにエクスポートします。
mysqldump -u mysql_username -p database_name block_content > block_migration/block_content.sql
mysqldump -u mysql_username -p database_name block_content__body > block_migration/block_content__body.sql
mysqldump -u mysql_username -p database_name block_content_field_data > block_migration/block_content_field_data.sql
mysqldump -u mysql_username -p database_name block_content_field_revision > block_migration/block_content_field_revision.sql
mysqldump -u mysql_username -p database_name block_content_revision > block_migration/block_content_revision.sql
mysqldump -u mysql_username -p database_name block_content_revision__body > block_migration/block_content_revision__body.sql
これらの新しいsqlファイルをgitまたはその他の方法でサイトBに転送します。これを頻繁に実行している場合は、空想を得て、上記のmysqldumpコマンドをpre-commitフックに入れることさえできます。
サイトB:
上記でエクスポートしたテーブルのドロップ/作成ロジックを含むコードをプルしたと仮定して、テーブルをデータベースにインポートします。
mysql -u mysql_username -p database_name < block_migration/block_content.sql
mysql -u mysql_username -p database_name < block_migration/block_content__body.sql
mysql -u mysql_username -p database_name < block_migration/block_content_field_data.sql
mysql -u mysql_username -p database_name < block_migration/block_content_field_revision.sql
mysql -u mysql_username -p database_name < block_migration/block_content_revision.sql
mysql -u mysql_username -p database_name < block_migration/block_content_revision__body.sql
キャッシュをクリアすることは常に良い考えです。 Drushを使用している場合:
drush cr
カスタムブロックは2つのエンティティで構成され、1つはプレースメントと実際のコンテンツ用です。 cmiでエクスポートできるのは、実際の配置のみです。コンテンツはできません。 REST経由でコンテンツを送信するか、別のブロックのuuidを手動で編集して一致させることができます。将来的には、Entity Pilot(entitypilot.com)を使用できるようになります-免責事項-これは私の製品です。
開発の一部として追加されたコンテンツをテストおよびライブ環境にもプッシュするための別のアプローチは、コンテンツをエクスポートするために Default Content モジュールを使用することです。コンテンツがインストールプロファイルの「コンテンツ」フォルダーにエクスポートされるように構築されており、モジュールが有効になっている場合は、サイトのインストール時に自動的にコンテンツを取り込みますが、一度に1つのアイテムをインポートすることもできます。更新フックなど、example.installまたはexample.profileに以下のコードを含めます。
<?php
/**
* Import a piece of content exported by default content module.
*/
function example_import_default_content($path_to_content_json) {
list($entity_type_id, $filename) = explode('/', $path_to_content_json);
$p = drupal_get_path('profile', 'guts');
$encoded_content = file_get_contents($p . '/content/' . $path_to_content_json);
$serializer = \Drupal::service('serializer');
$content = $serializer->decode($encoded_content, 'hal_json');
global $base_url;
$url = $base_url . base_path();
$content['_links']['type']['href'] = str_replace('http://drupal.org/', $url, $content['_links']['type']['href']);
$contents = $serializer->encode($content, 'hal_json');
$class = 'Drupal\\' . $entity_type_id . '\Entity\\' . str_replace(' ', '', ucwords(str_replace('_', ' ', $entity_type_id)));
$entity = $serializer->deserialize($contents, $class, 'hal_json', array('request_method' => 'POST'));
$entity->enforceIsNew(TRUE);
$entity->save();
}
IDが8のカスタムブロックをエクスポートします。
drush dcer block_content 8
(設定しない場合 Drush設定でプロファイルパスを設定 上記で指定する必要があります。)
そして、結果のエクスポートをexample.installファイルで次のように使用します。
<?php
/**
* Add the footer block content.
*
* Implements hook_update_N().
*/
function example_update_8001() {
example_import_default_content('block_content/136efd63-021e-42ea-8202-8b97305cc07f.json');
}
詳細は 更新フックでデフォルトのコンテンツを簡単に追加する を参照してください。
ここに投稿した皆さんに感謝します。私たちはこの問題(ブロック、ブロック構成、CMI)について本当に混乱していました。
ここでの情報を出発点として、次のスクリプトを作成しました(データベースのUUIDを修正する次のスクリプトをDrupal rootからdrush php-scriptで実行できます)。これは、ただし、使用するブロックは既に存在します(私たちのブロックはDrupal 6移行から取得されるため、問題ではありません)。スクリプトは、 'info'値がブロックごとに、別名「ラベル」は一意であるため、マイレージは異なる場合があります。
開発環境からエクスポートされた構成を本番環境でも使用できるように、新しいブロックの作成をスクリプト化する方法を理解する必要がありますが、それは別の話です。
<?php
use Drupal\Component\Serialization\Yaml;
// we need to parse all uuids from deploy dir and override local uuids
$dir = \Drupal::root() . '/' . config_get_config_directory('sync') . '/';
$files = scandir($dir);
\Drupal\Core\Database\Database::setActiveConnection();
$connection = \Drupal\Core\Database\Database::getConnection();
$logger = \Drupal::logger('code_driven_devel');
// Gather all 'block_content' blocks; store the label and uuid
$labelled_blocks_to_uuids = array();
$labels = array();
foreach($files as $file) {
$ext = substr($file, -4);
if ($ext == '.yml') {
$info = Yaml::decode(file_get_contents($dir . $file));
$name = substr($file, 0, -4);
$isblock = substr($name, 0, 5);
if($isblock == 'block') {
if(is_array($info) && array_key_exists('settings', $info)) {
$id = $info['settings']['id'];
$id_parts = explode(':', $id);
if ($id_parts[0] == 'block_content') {
$uuid = $id_parts[1];
$label = $info['settings']['label'];
if (strlen($label) > 0) {
$labelled_blocks_to_uuids[$label] = $uuid;
array_Push($labels, $label);
}
}
}
}
}
}
$logger->notice(t("Found " . count($labels) . " block_content config YML that may need to have their UUIDs synched..."));
$results = $connection->select('block_content_field_data', 't')
->fields('t')
->condition('info', $labels, 'IN')
->execute();
if ($results) {
foreach ($results as $record) {
$logger->notice(t("Updating UUID for block_content with id = " . $record->id . "..."));
$uuid = $labelled_blocks_to_uuids[$record->info];
$connection->update('block_content')
->fields(array(
'uuid' => $uuid,
))
->condition('id', $record->id, '=')
->execute();
$logger->notice(t("UUID for block_content with id = " . $record->id . " updated to " . $uuid));
}
}
これを解決する寄付モジュールを公開したところです。基本的に、モジュールは、カスタムブロック(コンテンツブロック)をラップする構成(固定ブロック)に基づいたタイプのブロックを提供します。固定ブロックは、デフォルトのコンテンツとしてWebサイト構成に保存されます。シナリオでは、カスタムブロックがサイトBに自動的に作成され、デフォルトのコンテンツが必要に応じてすぐに使用されます。
すべてがUIを介して行われ、特別なファイルやカスタムモジュールは必要ありません。 「固定ブロックコンテンツ」と名付け、次の場所で公開されています。