Drupal 8自定义模块-使用hook_update_N从YML文件安装其他配置

时间:2018-09-07 11:18:40

标签: module yaml drupal-8 configuration-management

我有一个自定义模块,该模块安装一组特定的配置-所有这些配置都存储在config/install文件夹中,这意味着它们是在安装模块时安装的。

该配置包括内容类型,段落,查看模式,表单模式,字段存储以及附加到内容类型和段落的字段等。该想法是使用此模块安装“功能”(博客)并在多个站点上使用它,并在我们向此功能添加更多内容时提供更新和扩展。

自从初始安装以来,您无法通过config/install文件夹添加更多配置,我一直在尝试找到一种通过更新挂钩导入其他配置文件的方法,该方法有效:

<?php

use \Symfony\Component\Yaml\Yaml;

/**
 * Installs the file upload element
 */
function MODULE_NAME_update_8002() {

  // Is the flaw with this the fact that the order of loading configurations now
  // matters and is a little bit more difficult to deal with?
  // NOTE:  YES. If, for example, you comment out the installing of the
  // field_storage for the field_cb_file, but try to add the field_cb_file to
  // the paragraph type, the update is successful and no errors are thrown.
  // This is basically me trying to re-create the drupal configuration management
  // system, without the dependency checks, etc. What is the PROPER way of
  // importing additional configuration from a module through an update?
  //  FIXME:  

  $configs_to_install = [
    'paragraphs.paragraphs_type.cbsf_file_download',
    'field.storage.paragraph.field_cb_file',
    'field.field.paragraph.cbsf_file_download.field_cb_file',
    'field.field.paragraph.cbsf_file_download.field_cb_heading',
    'field.field.paragraph.cbsf_file_download.field_cb_icon',
    'field.field.paragraph.cbsf_file_download.field_cb_text',
    'core.entity_form_display.paragraph.cbsf_file_download.default',
    'core.entity_view_display.paragraph.cbsf_file_download.default',
  ];

  foreach ($configs_to_install as $config_to_install) {
    $path = drupal_get_path('module', 'MODULE_NAME') . '/config/update_8002/' . $config_to_install . '.yml';
    $content = file_get_contents($path);
    $parsed_yml = Yaml::parse($content);

    $active_storage = \Drupal::service('config.storage');
    $active_storage->write($config_to_install, $parsed_yml);
  }
}

但是,此方法存在缺陷,因为它意味着如果彼此依赖,则必须以正确的顺序对配置文件进行排序,并且不会检查配置文件中存在的任何依赖关系。

是否有一种方法可以利用配置管理正确地导入配置,以同样的方式“遍历文件”?还是指向包含所有配置文件的文件夹并安装它们?


  

编辑:此方法还有其他问题-即使您已经按照相关性正确订购了文件,也不会创建数据库表。配置只是按原样“写入”,并且Drupal的其他部分似乎没有意识到已经创建了新实体,因此如果您要通过Drupal GUI创建实体,它们将无法运行否则会运行的任何功能。 。 绝对不是推荐的传输更复杂配置的方法。

1 个答案:

答案 0 :(得分:1)

我将这一步骤进一步推进-有一种方法可以使用EntityTypeManager类创建/更新配置。


2个链接在很大程度上帮助了我:

  

https://drupal.stackexchange.com/questions/164713/how-do-i-update-the-configuration-of-a-module

pwolanins底部的答案提供了一个功能,该功能可以更新配置(如果存在)或直接创建配置。

  

https://www.metaltoad.com/blog/programmatically-importing-drupal-8-field-configurations

此页面上的代码使您可以更清楚地了解正在发生的事情-对于要安装的每个配置,请通过各自的存储管理器运行YML文件,然后创建适当的实体配置,该配置将创建所有所需的数据库表。


我最终要做的是:

使用了pwolanins代码的略微修改版本,并创建了通用的配置更新程序功能-

function _update_or_install_config( String $prefix, String $update_id, String $module) {
  $updated = [];
  $created = [];

  /** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
  $config_manager = \Drupal::service('config.manager');
  $files = glob(drupal_get_path('module', $module) . '/config/update_' . $update_id. '/' . $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);
    }

    $type = $config_manager->getEntityTypeIdByName(basename($file));
    $entity_manager = $config_manager->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 [
    'udpated' => $updated,
    'created' => $created,
  ];
}

我将所有yml文件放在文件夹config/update_8002中,然后利用此函数在hook_update_N函数中循环配置文件:

function MODULE_NAME_update_8002() {

  $configs_to_install = [
    'paragraphs.paragraphs_type.cbsf_file_download',
    'core.entity_form_display.paragraph.cbsf_file_download.default',
    'core.entity_view_display.paragraph.cbsf_file_download.default',
    'field.storage.paragraph.field_cb_file',
    'field.field.paragraph.cbsf_file_download.field_cb_file',
    'field.field.paragraph.cbsf_file_download.field_cb_heading',
    'field.field.paragraph.cbsf_file_download.field_cb_icon',
    'field.field.paragraph.cbsf_file_download.field_cb_text',
  ];

  foreach ($configs_to_install as $config_to_install) {
    _update_or_install_config('paragraphs.paragraphs_type', '8002', 'MODULE_NAME');
    _update_or_install_config('field.storage.paragraph', '8002', 'MODULE_NAME');
    _update_or_install_config('field.field.paragraph', '8002', 'MODULE_NAME');
    _update_or_install_config('core.entity_view_display.paragraph', '8002', 'MODULE_NAME');
    _update_or_install_config('core.entity_form_display.paragraph', '8002', 'MODULE_NAME');
  }

}

请注意,_update_or_install_config函数遍历文件夹中与特定实体类型管理器匹配的所有配置-因此,您应该只在函数中包括前缀,以及所有导入配置的YML文件将会包含相同的类型。

相关问题