From a30616fb875f8fde62a72d854960e491ff62511a Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Sun, 3 Mar 2024 16:12:27 +0000
Subject: [PATCH] Issue #3422603 by b2f, godotislate: Fixing source IDs with
 spaces in Sql.php

(cherry picked from commit 56f8d7594cf742ab4ff1ce83a9874d7198f4f8f8)
---
 .../migrate/src/Plugin/migrate/id_map/Sql.php | 15 +++++--
 .../tests/src/Unit/MigrateSqlIdMapTest.php    | 40 ++++++++++++++++++-
 2 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php b/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
index 52b89c9999da..54d55cfb0332 100644
--- a/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
+++ b/core/modules/migrate/src/Plugin/migrate/id_map/Sql.php
@@ -590,14 +590,23 @@ public function getRowsNeedingUpdate($count) {
   public function lookupSourceId(array $destination_id_values) {
     $source_id_fields = $this->sourceIdFields();
     $query = $this->getDatabase()->select($this->mapTableName(), 'map');
+    // To allow source field names to be defined with spaces and special
+    // characters, create an alias map of column alias to source field name,
+    // since SQL column aliases do not support spaces or special characters.
+    $alias_map = [];
     foreach ($source_id_fields as $source_field_name => $id_map_field_name) {
-      $query->addField('map', $id_map_field_name, $source_field_name);
+      $alias = $query->addField('map', $id_map_field_name);
+      $alias_map[$alias] = $source_field_name;
     }
     foreach ($this->destinationIdFields() as $field_name => $destination_id) {
       $query->condition("map.$destination_id", $destination_id_values[$field_name], '=');
     }
-    $result = $query->execute();
-    return $result->fetchAssoc() ?: [];
+    $result = $query->execute()->fetchAssoc() ?: [];
+    $source_ids = [];
+    foreach ($result as $alias => $id) {
+      $source_ids[$alias_map[$alias]] = $id;
+    }
+    return $source_ids;
   }
 
   /**
diff --git a/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php b/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php
index 0ba79e1aab5d..afcb0cde8dce 100644
--- a/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php
+++ b/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php
@@ -625,6 +625,42 @@ public function lookupSourceIdMappingDataProvider() {
    * @dataProvider lookupSourceIdMappingDataProvider
    */
   public function testLookupSourceIdMapping($num_source_fields, $num_destination_fields) {
+    $source_id_property_prefix = 'source_id_property_';
+    $this->doTestLookupSourceIdMapping($num_source_fields, $num_destination_fields, $source_id_property_prefix);
+  }
+
+  /**
+   * Performs the source ID test on source and destination fields.
+   *
+   * This performs same test as ::testLookupSourceIdMapping, except with source
+   * property names including spaces and special characters not allowed in SQL
+   * column aliases.
+   *
+   * @param int $num_source_fields
+   *   Number of source fields to test.
+   * @param int $num_destination_fields
+   *   Number of destination fields to test.
+   *
+   * @dataProvider lookupSourceIdMappingDataProvider
+   */
+  public function testLookupSourceIdMappingNonSqlCharacters($num_source_fields, $num_destination_fields) {
+    $source_id_property_prefix = '$ource id property * ';
+    $this->doTestLookupSourceIdMapping($num_source_fields, $num_destination_fields, $source_id_property_prefix);
+  }
+
+  /**
+   * Performs the source ID test on source and destination fields.
+   *
+   * @param int $num_source_fields
+   *   Number of source fields to test.
+   * @param int $num_destination_fields
+   *   Number of destination fields to test.
+   * @param string $source_id_property_prefix
+   *   Prefix for the source ID properties.
+   *
+   * @dataProvider lookupSourceIdMappingDataProvider
+   */
+  public function doTestLookupSourceIdMapping(int $num_source_fields, int $num_destination_fields, string $source_id_property_prefix): void {
     // Adjust the migration configuration according to the number of source and
     // destination fields.
     $this->sourceIds = [];
@@ -635,8 +671,8 @@ public function testLookupSourceIdMapping($num_source_fields, $num_destination_f
     for ($i = 1; $i <= $num_source_fields; $i++) {
       $row["sourceid$i"] = "source_id_value_$i";
       $source_ids_values = [$row["sourceid$i"]];
-      $expected_result["source_id_property_$i"] = "source_id_value_$i";
-      $this->sourceIds["source_id_property_$i"] = [];
+      $expected_result[$source_id_property_prefix . $i] = "source_id_value_$i";
+      $this->sourceIds[$source_id_property_prefix . $i] = [];
     }
     $destination_id_values = [];
     $nonexistent_id_values = [];
-- 
GitLab