フィールドタイプマイグレーション


異なるフィールドタイプの間でデータを移動する方法が複数あります.この簡単なチュートリアルでは、可能な1つの方法について明記されます.

Field is a Drupal core module and it’s part of a list of different ways to represent data in Drupal.


このプロセスには次のものが含まれます.
  • カスタムモジュールの作成.
  • 移行変数の準備
  • 既存のデータの保存
  • フィールド設定ストレージの取得
  • フィールドの設定
  • 古い構成を削除します.
  • 新しいフィールドの設定にデータを挿入します.
  • 移行を実行します.
  • 必要条件

  • 新鮮であるか既存のDrupal 9.0プロジェクト.
  • Drush CLIツールcomposer require drush/drush )
  • 心に留めておくべきこと

  • このチュートリアルでは、フィールドを数値(整数)からテキスト(フォーマット)に変換しようとします.See documentation for list of field types .
  • 1 -カスタムモジュールの作成
    があるabundant list of documentations Drupalでカスタムモジュールを作成するとき.しかし、私たちの目的のための最小のフォルダ構造はfield_migration_medium ):
    field_migration_medium/
      field_migration_medium.info.yml
      field_migration_medium.install
    
    field_migration_medium.install ファイルを使用しますhook_update_N function Drupalにこのカスタムモジュールの既存のデータベース更新を知っているようにするために.
    <?php
    /**
    * hook_update_N()
    */
    function field_migration_medium_update_9001() {
    }
    

    N donates the update ID and Drupal keeps track of this for each module. See the documentation for more info.


    2 -移行変数の準備
    現在のフィールド型と新しいフィールド型を特定する必要があります.これらの値を特定するために、我々は何を見なければなりませんかField Config Storage and Field Config 平均値
    エーbundle Drupalでは、数値、テキスト、Boolean ...等のような様々なフィールド型から成ります.これらのフィールド型のそれぞれには、既定の設定設定がありますField Storage Configuration ) と特定のField Configuration ).
    例えば、私はfield_number つの異なるコンテンツタイプarticle , page and medium . これらのコンテンツタイプのすべてが同じfield_number しかし、グローバル設定では、各コンテンツタイプには、field_number .
    以下の違いを説明するには、以下の各オブジェクトのスニペットです.

  • グローバルな設定field_number .
  • Drupal\field\Entity\FieldStorageConfig Object                                
      (                                                                            
          [id:protected] => node.field_number                                      
          [field_name:protected] => field_number                                   
          [entity_type:protected] => node                                          
          [type:protected] => integer                                              
          [module:protected] => core
    

  • 特定の設定article コンテンツタイプ.
  • Drupal\field\Entity\FieldConfig Object                                
      (                                                                            
          [deleted:protected] =>                                                   
          [fieldStorage:protected] =>                                              
          [id:protected] => node.article.field_number                              
          [field_name:protected] => field_number                                   
          [field_type:protected] => integer                                        
          [entity_type:protected] => node                                          
          [bundle:protected] => article                                            
          [label:protected] => Number                                              
          [description:protected] =>                                               
          [settings:protected] => Array                                            
              (                                                                    
                  [min] =>                                                         
                  [max] =>                                                         
                  [prefix] =>                                                      
                  [suffix] =>                                                      
              )
    

  • 特定の設定page コンテンツタイプ.
  • pageDrupal\field\Entity\FieldConfig Object                                   
      (                                                                            
          [deleted:protected] =>                                                   
          [fieldStorage:protected] =>                                              
          [id:protected] => node.page.field_number                                 
          [field_name:protected] => field_number                                   
          [field_type:protected] => integer                                        
          [entity_type:protected] => node                                          
          [bundle:protected] => page                                               
          [label:protected] => Number                                              
          [description:protected] =>                                               
          [settings:protected] => Array                                            
              (                                                                    
                  [min] => 0                                                       
                  [max] => 11                                                      
                  [prefix] =>                                                      
                  [suffix] =>                                                      
              )
    

  • 特定の設定medium コンテンツタイプ.
  • mediumDrupal\field\Entity\FieldConfig Object                                 
      (                                                                            
          [deleted:protected] =>                                                   
          [fieldStorage:protected] =>                                              
          [id:protected] => node.medium.field_number                               
          [field_name:protected] => field_number                                   
          [field_type:protected] => integer                                        
          [entity_type:protected] => node                                          
          [bundle:protected] => medium                                             
          [label:protected] => Number Text                                         
          [description:protected] => This is medium number text.                   
          [settings:protected] => Array                                            
              (                                                                    
                  [min] =>                                                         
                  [max] =>                                                         
                  [prefix] =>                                                      
                  [suffix] =>                                                      
              )
    

    There are subtle changes in each content type, such as id, bundle, label, description and settings. The common values in these content types are field_name, field_type and entity_type.


    それを念頭に置いて、移行変数を続けて定義しましょう.
    移行変数は以下の通りです:
  • エンティティ型node このチュートリアルでは.
  • OldRuleフィールドのマシン名.マシン名は/admin/reports/fields . 私はこの分野をfield_number .
  • データベース内のOldHandフィールドのテーブル名です.テーブル名は、エンティティ名とoldholdフィールドマシン名からなりますnode__field_number
  • オルディフィールドのリビジョン表を返します.また、それはoldtleフィールドの実体名とマシン名を持ちます.node_revision__field_number
  • 新しいフィールドを格納する配列.
  • $entityType = 'node'; 
    $oldFieldName = 'field_number';
    $table = $entityType. '__' . $oldFieldName;
    $revisionTable = $entityType. '_revision__' . $oldFieldName;
    $newFieldsArray = [];
    
    3 -データとリビジョンデータを配列に格納する
    $rows = NULL;
    $revisionRows = NULL;
    if ($database->schema()->tableExists($table)) {
        $rows = $database->select($table, 'n')->fields('n')->execute()->fetchAll();
        $revisionRows = $database->select($revisionTable, 'n')->fields('n')->execute()->fetchAll();
    }
    
    4 -フィールドストレージの設定を取得する
    単一のフィールドストレージ設定があるので、$entityType and $oldFieldName to loadByName($entity_type_id, $field_name) method .
    $fieldStorage = FieldStorageConfig::loadByName($entityType, $oldFieldName);
    
  • 新しいフィールドストレージの設定
  • $newFieldStorage = $fieldStorage->toArray();
    $newFieldStorage['type'] = 'text';
    $newFieldStorage['settings'] = array(
       'max_length' => 255
    )
    

    Note: To get a list of the bundles that uses the field storage config, getBundles() method can be called like this $fieldStorage->getBundles() as we will see below.


    5 -フィールド設定を取得する
  • すべてのバンドルを取得field_number を繰り返し実行する.

  • Load the name それぞれの特定のフィールドの設定loadByName($entity_type_id, $bundle, $field_name)
  • foreach ($fieldStorage->getBundles() as $bundle => $label) {
        $field = FieldConfig::loadByName($entityType, $bundle, $oldFieldName);
        // Turn the result into an array
        $newField = $field->toArray();
        // Update the field_type from `number` to `text`
        $newField['field_type'] = 'text';
        // Update the settings of this new field -- Optional
        $newField['settings'] = array(
               'max_length' => 255
        );
        // Store the result into an array
        $newFieldsArray[] = $newField;
    }
    
    古い構成を削除する
  • フィールドストレージの削除
  • $fieldStorage->delete();
    
  • すべてのフィールドをバッチでパージする
  • field_purge_batch(N); // N is the batch number
    
    7 -新しいフィールドの設定にデータを挿入する
  • 新しいフィールドストレージの設定
  • $newFieldStorage = FieldStorageConfig::create($newFieldStorage);
    $newFieldStorage->save();
    
  • 新しいフィールド構成を作成する
  • foreach ($newFieldsArray as $field) {
       $fieldConfig = FieldConfig::create($field);
       $fieldConfig->save();
    }
    
  • 新しいフィールドにデータを挿入する
  • // Row data
    if (!is_null($rows)) {
      foreach ($rows as $row) {
       $database->insert($table)->fields((array) $row)->execute();
      }
    }
    // Revision data
    if (!is_null($revision_rows)) {
      foreach ($revision_rows as $row) {
        $database->insert($revisionTable)->fields((array) $row)->execute();
      }
    }
    
    8 -データベース更新を実行する
    このアップデートはdrushやdrupal cliコマンドを使用して行うことができます.注:データベースをバックアップします.
    // Drupal CLI
    bin/drupal upex
    // Drush CLI
    bin/drush updb
    
    完全なコード断片
    <?php
    
    use \Drupal\field\Entity\FieldConfig;
    use \Drupal\field\Entity\FieldStorageConfig;
    
    /**
     * Change field_number from Number (integer) to Text (formatted)
     */
    function field_migration_medium_update_9001() {
    
      $entityType = 'node';
      $oldFieldName = 'field_number';
      $table = $entityType . '__' . $oldFieldName;
      $revisionTable = $entityType . '_revision__' . $oldFieldName;
      $newFieldsArray = [];
    
      $database = \Drupal::database();
    
      $rows = NULL;
      $revisionRows = NULL;
      if ($database->schema()->tableExists($table)) {
        $rows = $database->select($table, 'n')->fields('n')->execute()
          ->fetchAll();
        $revisionRows = $database->select($revisionTable, 'n')->fields('n')->execute()
          ->fetchAll();
      }
    
      // Get field storage config.
      $fieldStorage = FieldStorageConfig::loadByName($entityType, $oldFieldName);
    
      // Check if field storage config exist.
      if (is_null($fieldStorage)) {
        return t('Field Storage does not exist');
      }
    
      $newFieldStorage = $fieldStorage->toArray();
      $newFieldStorage['type'] = 'text';
      $newFieldStorage['settings'] = array(
        'max_length' => 255
      );
    
      foreach ($fieldStorage->getBundles() as $bundle => $label) {
        $field = FieldConfig::loadByName($entityType, $bundle, $oldFieldName);
    
        $newField = $field->toArray();
        $newField['field_type'] = 'text';
        $newField['settings'] = array(
          'max_length' => 255
        );
        $newFieldsArray[] = $newField;
      }
    
      $fieldStorage->delete();
      field_purge_batch(40);
    
      // Create new field storage.
      $newFieldStorage = FieldStorageConfig::create($newFieldStorage);
      $newFieldStorage->save();
    
      // Create new fields.
      foreach ($newFieldsArray as $field) {
        $fieldConfig = FieldConfig::create($field);
        $fieldConfig->save();
      }
    
      // Restore existing data in new fields.
      if (!is_null($rows)) {
        foreach ($rows as $row) {
        $database->insert($table)
                 ->fields((array) $row)
                 ->execute();
        }
      }
    
      if (!is_null($revisionRows)) {
        foreach ($revisionRows as $row) {
          $database->insert($revisionTable)
                   ->fields((array) $row)
                   ->execute();
         }
      }
    }
    
    最後の思考
    データベース更新が実行されると、Drupalは各モジュールの更新IDを追跡します.このUpdate ID can be set to specific version drushを使って.慎重にお使いください.
    drush ev "drupal_set_installed_schema_version(module, version)"
    
    ハッピーコーディング