Unverified Commit b930c804 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2225587 by quietone, Jo Fitzgerald, alexpott, heddn, Pavan B S,...

Issue #2225587 by quietone, Jo Fitzgerald, alexpott, heddn, Pavan B S, maxocub, phenaproxima, Gábor Hojtsy, ao2: Migrate D6 i18n menu links
parent b61e2a65
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
id: d6_language_content_menu_settings
label: Drupal 6 language content menu settings
migration_tags:
  - Drupal 6
  - Configuration
source:
  plugin: extension
  name: i18nmenu
  constants:
    target_type: 'menu_link_content'
    langcode: 'site_default'
process:
  target_entity_type_id: 'constants/target_type'
  # menu_link_content has a bundle key but no bundle support so use the entity
  # type as the bundle.
  target_bundle: 'constants/target_type'
  default_langcode: 'constants/langcode'
  # Drupal 6 menus are translated when the i18nmenu module is enabled.
  language_alterable: status
destination:
  plugin: entity:language_content_settings
+68 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Tests\language\Kernel\Migrate\d6;

use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\language\Entity\ContentLanguageSettings;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;

/**
 * Tests migration of the ability to translate menu content.
 *
 * @group migrate_drupal_6
 */
class MigrateLanguageContentMenuSettingsTest extends MigrateDrupal6TestBase {

  /**
   * {@inheritdoc}
   */
  public static $modules = [
    'language',
    'content_translation',
    'menu_link_content',
  ];

  /**
   * {@inheritdoc}
   */
  protected function setUp() {
    parent::setUp();
    // Create some languages.
    ConfigurableLanguage::createFromLangcode('en')->save();
    ConfigurableLanguage::createFromLangcode('fr')->save();
    $this->executeMigrations(['d6_language_content_menu_settings']);
  }

  /**
   * Tests migration of menu translation ability.
   */
  public function testLanguageMenuContent() {
    $config = ContentLanguageSettings::load('menu_link_content.menu_link_content');
    $this->assertInstanceOf(ContentLanguageSettings::class, $config);
    $this->assertSame('menu_link_content', $config->getTargetEntityTypeId());
    $this->assertSame('menu_link_content', $config->getTargetBundle());
    $this->assertSame(LanguageInterface::LANGCODE_SITE_DEFAULT, $config->getDefaultLangcode());
    $this->assertTrue($config->isLanguageAlterable());

    // Test that menus are not alterable when the i18nmenu is not enabled.
    $this->sourceDatabase->update('system')
      ->fields(['status' => 0])
      ->condition('name', 'i18nmenu')
      ->execute();

    /** @var \Drupal\migrate\Plugin\MigrationInterface $migration */
    $migration = $this->getMigration('d6_language_content_menu_settings');
    // Indicate we're rerunning a migration that's already run.
    $migration->getIdMap()->prepareUpdate();
    $this->executeMigration($migration);

    $config = ContentLanguageSettings::load('menu_link_content.menu_link_content');
    $this->assertInstanceOf(ContentLanguageSettings::class, $config);
    $this->assertSame('menu_link_content', $config->getTargetEntityTypeId());
    $this->assertSame('menu_link_content', $config->getTargetBundle());
    $this->assertSame(LanguageInterface::LANGCODE_SITE_DEFAULT, $config->getDefaultLangcode());
    $this->assertFalse($config->isLanguageAlterable());
  }

}
+54 −0
Original line number Diff line number Diff line
id: d6_menu_links_translation
label: Menu links
migration_tags:
  - Drupal 6
  - Content
source:
  plugin: d6_menu_link_translation
process:
  id: mlid
  langcode: language
  title:
    -
      plugin: callback
      source:
        - title_translated
        - link_title
      callable: array_filter
    -
      plugin: callback
      callable: current
  description:
    -
      plugin: callback
      source:
        - description_translated
        - description
      callable: array_filter
    -
      plugin: callback
      callable: current
  menu_name:
    -
      plugin: migration_lookup
      # The menu migration is in the system module.
      migration: d6_menu
      source: menu_name
    -
      plugin: skip_on_empty
      method: row
    -
      plugin: static_map
      map:
        management: admin
      bypass: true
destination:
  plugin: entity:menu_link_content
  default_bundle: menu_link_content
  no_stub: true
  translations: true
migration_dependencies:
  required:
    - language
    - d6_menu
    - d6_menu_links
+98 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\menu_link_content\Plugin\migrate\source\d6;

use Drupal\migrate\Row;
use Drupal\menu_link_content\Plugin\migrate\source\MenuLink;

/**
 * Gets Menu link translations from source database.
 *
 * @MigrateSource(
 *   id = "d6_menu_link_translation",
 *   source_module = "i18nmenu"
 * )
 */
class MenuLinkTranslation extends MenuLink {

  /**
   * {@inheritdoc}
   */
  public function query() {
    // Ideally, the query would return rows for each language for each menu link
    // with the translations for both the title and description or just the
    // title translation or just the description translation. That query quickly
    // became complex and would be difficult to maintain.
    // Therefore, build a query based on i18nstrings table where each row has
    // the translation for only one property, either title or description. The
    // method prepareRow() is then used to obtain the translation for the other
    // property.
    // The query starts with the same query as menu_link.
    $query = parent::query();

    // Add in the property, which is either title or description. Cast the mlid
    // to text so PostgreSQL can make the join.
    $query->leftJoin('i18n_strings', 'i18n', 'CAST(ml.mlid as CHAR(255)) = i18n.objectid');
    $query->isNotNull('i18n.lid');
    $query->addField('i18n', 'lid');
    $query->addField('i18n', 'property');

    // Add in the translation for the property.
    $query->innerJoin('locales_target', 'lt', 'i18n.lid = lt.lid');
    $query->addField('lt', 'language');
    $query->addField('lt', 'translation');
    return $query;
  }

  /**
   * {@inheritdoc}
   */
  public function prepareRow(Row $row) {
    $language = $row->getSourceProperty('language');
    $mlid = $row->getSourceProperty('mlid');

    // If this row has been migrated it is a duplicate then skip it.
    if ($this->idMap->lookupDestinationIds(['mlid' => $mlid, 'language' => $language])) {
      return FALSE;
    }

    // Save the translation for this property.
    $property = $row->getSourceProperty('property');
    $row->setSourceProperty($property . '_translated', $row->getSourceProperty('translation'));

    // Get the translation, if one exists, for the property not already in the
    // row.
    $other_property = ($property == 'title') ? 'description' : 'title';
    $query = $this->select('i18n_strings', 'i18n')
      ->fields('i18n', ['lid'])
      ->condition('i18n.property', $other_property)
      ->condition('i18n.objectid', $mlid);
    $query->leftJoin('locales_target', 'lt', 'i18n.lid = lt.lid');
    $query->condition('lt.language', $language);
    $query->addField('lt', 'translation');
    $results = $query->execute()->fetchAssoc();
    $row->setSourceProperty($other_property . '_translated', $results['translation']);
    parent::prepareRow($row);
  }

  /**
   * {@inheritdoc}
   */
  public function fields() {
    $fields = [
      'language' => $this->t('Language for this menu.'),
      'title_translated' => $this->t('Menu link title translation.'),
      'description_translated' => $this->t('Menu link description translation.'),
    ];
    return parent::fields() + $fields;
  }

  /**
   * {@inheritdoc}
   */
  public function getIds() {
    $ids['language']['type'] = 'string';
    return parent::getIds() + $ids;
  }

}
+4 −1
Original line number Diff line number Diff line
@@ -84,7 +84,7 @@ protected function assertEntity($id, $title, $menu, $description, $enabled, $exp
   * Tests migration of menu links.
   */
  public function testMenuLinks() {
    $this->assertEntity('138', 'Test 1', 'secondary-links', 'Test menu link 1', TRUE, FALSE, ['attributes' => ['title' => 'Test menu link 1']], 'internal:/user/login', -50);
    $this->assertEntity('138', 'Test 1', 'secondary-links', 'Test menu link 1', TRUE, FALSE, ['attributes' => ['title' => 'Test menu link 1'], 'langcode' => 'en'], 'internal:/user/login', -50);
    $this->assertEntity('139', 'Test 2', 'secondary-links', 'Test menu link 2', TRUE, TRUE, ['query' => 'foo=bar', 'attributes' => ['title' => 'Test menu link 2']], 'internal:/admin', -49);
    $this->assertEntity('140', 'Drupal.org', 'secondary-links', NULL, TRUE, FALSE, ['attributes' => ['title' => '']], 'https://www.drupal.org', -50);

@@ -96,6 +96,9 @@ public function testMenuLinks() {
    $this->assertEntity('460', 'Le Vrai McCoy', 'primary-links', NULL, TRUE, FALSE, ['attributes' => ['title' => ''], 'alter' => TRUE], 'entity:node/10', 0);
    $this->assertEntity('461', 'Abantu zulu', 'primary-links', NULL, TRUE, FALSE, ['attributes' => ['title' => ''], 'alter' => TRUE], 'entity:node/12', 0);
    $this->assertEntity('462', 'The Zulu People', 'primary-links', NULL, TRUE, FALSE, ['attributes' => ['title' => ''], 'alter' => TRUE], 'entity:node/12', 0);

    // Test the migration of menu links translation.
    $this->assertEntity('463', 'fr - Test 1', 'secondary-links', 'fr - Test menu link 1', TRUE, FALSE, ['attributes' => ['title' => 'fr - Test menu link 1'], 'langcode' => 'fr', 'alter' => TRUE], 'internal:/user/login', -49);
  }

}
Loading