Commit e7722cff authored by quietone's avatar quietone Committed by Joachim Noreiko
Browse files

Issue #2953036 by quietone: Added migrate support for Drupal 7 => Drupal 8.

parent b3d39fb8
Loading
Loading
Loading
Loading
+22 −0
Changes for inline_entity_form.module: 22 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -15,6 +15,10 @@ use Drupal\inline_entity_form\ElementSubmit;
use Drupal\inline_entity_form\WidgetSubmit;
use Drupal\inline_entity_form\Form\EntityInlineForm;
use Drupal\inline_entity_form\Plugin\Field\FieldWidget\InlineEntityFormComplex;
use Drupal\inline_entity_form\MigrationHelper;
use Drupal\migrate\Plugin\MigrateSourceInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;

/**
 * Implements hook_entity_type_build().
@@ -442,3 +446,21 @@ function template_preprocess_inline_entity_form_entity_table(array &$variables)
    ] + $rows;
  }
}


/**
 * Implements hook_migrate_prepare_row().
 */
function inline_entity_form_migrate_prepare_row(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) {
  \Drupal::classResolver(MigrationHelper::class)
    ->alterRow($row, $source, $migration);
}


/**
 * Implements hook_migration_plugins_alter().
 */
function inline_entity_form_migration_plugins_alter(array &$migrations) {
  \Drupal::classResolver(MigrationHelper::class)
    ->alterPlugins($migrations);
}
+135 −0
Changes for src/MigrationHelper.php: 135 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Drupal\inline_entity_form;

use Drupal\Component\Utility\NestedArray;
use Drupal\field\Plugin\migrate\source\d7\FieldInstance;
use Drupal\field\Plugin\migrate\source\d7\FieldInstancePerFormDisplay;
use Drupal\migrate\Exception\RequirementsException;
use Drupal\migrate\Plugin\MigrateSourceInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;

/**
 * Helper for migration hooks in inline_entity_form.module.
 */
class MigrationHelper {

  /**
   * Alters the field migrations for the inline_entity_form widget.
   *
   * @param array $migrations
   *   An array of migrations.
   *
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   */
  public function alterPlugins(array &$migrations) {
    foreach ($migrations as &$migration) {
      /** @var \Drupal\migrate\Plugin\MigratePluginManager $migration_plugin_manager */
      $migration_plugin_manager = \Drupal::service('plugin.manager.migration');
      $migration_stub = $migration_plugin_manager->createStubMigration($migration);
      /** @var \Drupal\migrate\Plugin\MigrateSourcePluginManager $source_plugin_manager */
      $source_plugin_manager = \Drupal::service('plugin.manager.migrate.source');
      $source = NULL;
      $configuration = $migration['source'];
      $source = $source_plugin_manager->createInstance($migration['source']['plugin'], $configuration, $migration_stub);
      if ($source) {
        // Field instance.
        if (get_class($source) === FieldInstance::class) {
          $settings[] = $migration['process']['settings'];
          $addition = [
            'inline_entity_form' => [
              'plugin' => 'inline_entity_form_field_instance_settings',
            ],
          ];
          $settings = NestedArray::mergeDeepArray([$settings, $addition], TRUE);
          $migration['process']['settings'] = $settings;
        }
        if (is_a($source, FieldInstancePerFormDisplay::class)) {
          $addition = [
            'inline_entity_form_single' => 'inline_entity_form_simple',
            'inline_entity_form' => 'inline_entity_form_complex',
          ];
          $migration['process']['options/type']['type']['map'] = array_merge($migration['process']['options/type']['type']['map'], $addition);
        }
      }
    }
  }

  /**
   * Adds all bundles for the entity type to the row.
   *
   * Drupal 7 inline_entity_form set the target bundles to an empty array to
   * indicate all bundles are referenced. In Drupal 8+ all the target bundles
   * are listed in the handler settings. Therefore, when the target bundle is an
   * empty array  get all the bundles and put them on the row.
   *
   * @param \Drupal\migrate\Row $row
   *   The current row.
   * @param \Drupal\migrate\Plugin\MigrateSourceInterface $source
   *   The source for this migration.
   * @param \Drupal\migrate\Plugin\MigrationInterface $migration
   *   The migration.
   *
   * @throws \Exception
   */
  public function alterRow(Row $row, MigrateSourceInterface $source, MigrationInterface $migration) {
    if ($source) {
      if (get_class($source) === FieldInstance::class && $row->get('type') === 'entityreference') {
        $widget = $row->get('widget/type');
        if ($widget === 'inline_entity_form_single' || $widget === 'inline_entity_form') {
          $data = $row->get('field_definition/data');
          $definition = unserialize($data);
          if (empty($definition['settings']['handler_settings']['target_bundles'])) {
            $entity_type = $row->get('entity_type');
            $bundles = $this->getBundles($source, $entity_type);
          }
        }
      }
      $bundles = $bundles ?? [];
      $row->setSourceProperty('target_bundles', $bundles);
    }
  }

  /**
   * Helper to get the bundles for an entity type.
   *
   * This currently only works for nodes. To add other entity types add a new
   * case to the switch statement below and either use a query to get the
   * bundles or hard code the values for you source site.
   *
   * @param \Drupal\migrate\Plugin\MigrateSourceInterface $source_plugin
   *   The source plugin.
   * @param string $entity_type
   *   The entity type.
   *
   * @return array
   *   The product types.
   */
  protected function getBundles(MigrateSourceInterface $source_plugin, $entity_type) {
    $bundles = NULL;
    $connection = NULL;

    try {
      $connection = $source_plugin->getDatabase();
    }
    catch (RequirementsException $e) {
    }

    if ($connection) {
      switch ($entity_type) {
        case 'node':
          if ($connection->schema()->tableExists('node_type')) {
            $query = $connection->select('node_type', 't')->fields('t');
            $bundles = $query->execute()->fetchCol();
          }
          break;

        default:
          break;
      }
    }
    return $bundles;
  }

}
+38 −0
Changes for src/Plugin/migrate/process/InlineFormEntityFieldInstanceSettings.php: 38 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Drupal\inline_entity_form\Plugin\migrate\process;

use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;

/**
 * Configure field instance settings for inline_form_entity.
 *
 * @MigrateProcessPlugin(
 *   id = "inline_entity_form_field_instance_settings"
 * )
 */
class InlineFormEntityFieldInstanceSettings extends ProcessPluginBase {

  /**
   * {@inheritdoc}
   */
  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    if ($row->getSourceProperty('type') === 'entityreference') {
      $widget = $row->get('widget/type');
      if ($widget === 'inline_entity_form_single' || $widget === 'inline_entity_form') {
        $target_bundles = $row->get('target_bundles');
        // The previous process,
        // \Drupal\Tests\field\Unit\Plugin\migrate\process\d7\FieldInstanceSettingsTest
        // sets target_bundles to NULL when the source target_bundles is an
        // empty array.
        if (is_null($value['handler_settings']['target_bundles'])) {
          $value['handler_settings']['target_bundles'] = $target_bundles;
        }
      }
    }
    return $value;
  }

}
+3443 −0

File added.

Preview size limit exceeded, changes collapsed.

+100 −0
Changes for tests/src/Kernel/Migrate/MigrateFieldInstanceTest.php: 100 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Drupal\Tests\inline_entity_form\Kernel\Migrate;

use Drupal\field\Entity\FieldConfig;
use Drupal\field\FieldConfigInterface;

/**
 * Tests migration of inline_entity_form field instances.
 *
 * @group inline_entity_form
 */
class MigrateFieldInstanceTest extends MigrateTestBase {

  /**
   * {@inheritdoc}
   */
  public static $modules = [
    'inline_entity_form',
    'node',
    'text',
  ];

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();
    $this->installConfig('node');
    $this->executeMigrations([
      'd7_node_type',
      'd7_field',
      'd7_field_instance',
    ]);
  }

  /**
   * Asserts various aspects of a field config entity.
   *
   * @param string $id
   *   The entity ID in the form ENTITY_TYPE.BUNDLE.FIELD_NAME.
   * @param string $expected_label
   *   The expected field label.
   * @param string $expected_field_type
   *   The expected field type.
   * @param bool $is_required
   *   Whether or not the field is required.
   * @param bool $expected_translatable
   *   Whether or not the field is expected to be translatable.
   */
  protected function assertEntity($id, $expected_label, $expected_field_type, $is_required, $expected_translatable) {
    list ($expected_entity_type, $expected_bundle, $expected_name) = explode('.', $id);

    /** @var \Drupal\field\FieldConfigInterface $field */
    $field = FieldConfig::load($id);
    $this->assertInstanceOf(FieldConfigInterface::class, $field);
    $this->assertEquals($expected_label, $field->label());
    $this->assertEquals($expected_field_type, $field->getType());
    $this->assertEquals($expected_entity_type, $field->getTargetEntityTypeId());
    $this->assertEquals($expected_bundle, $field->getTargetBundle());
    $this->assertEquals($expected_name, $field->getName());
    $this->assertEquals($is_required, $field->isRequired());
    $this->assertEquals($expected_entity_type . '.' . $expected_name, $field->getFieldStorageDefinition()->id());
    $this->assertEquals($expected_translatable, $field->isTranslatable());
  }

  /**
   * Asserts the settings of an entity reference field config entity.
   *
   * @param string $id
   *   The entity ID in the form ENTITY_TYPE.BUNDLE.FIELD_NAME.
   * @param string[] $target_bundles
   *   An array of expected target bundles.
   * @param string[] $sort
   *   An array of expected sort parameters.
   */
  protected function assertEntityReferenceFields($id, array $target_bundles, array $sort) {
    $field = FieldConfig::load($id);
    $handler_settings = $field->getSetting('handler_settings');
    $this->assertArrayHasKey('target_bundles', $handler_settings);
    foreach ($handler_settings['target_bundles'] as $target_bundle) {
      $this->assertContains($target_bundle, $target_bundles);
    }
    $this->assertArrayHasKey('sort', $handler_settings);
    $this->assertSame($sort, $handler_settings['sort']);
  }

  /**
   * Tests migrating D7 field instances to field_config entities.
   */
  public function testFieldInstances() {
    $this->assertEntity('node.test.body', 'Body', 'text_with_summary', FALSE, FALSE);
    $this->assertEntity('node.test.field_single', 'single', 'entity_reference', FALSE, FALSE);
    $this->assertEntity('node.test.field_multiple', 'multiple', 'entity_reference', FALSE, FALSE);

    $this->assertEntityReferenceFields('node.test.field_single', ['page'], ['field' => 'language', 'direction' => 'DESC']);
    $this->assertEntityReferenceFields('node.test.field_multiple', ['page', 'test'], ['field' => '_none', 'direction' => 'ASC']);
  }

}
Loading