Browse Source

raw-sources: inject flat IDs in source.

Frederic G. MARAND 7 years ago
parent
commit
de6b40a623

+ 5 - 0
reinstall.services.yml

@@ -36,6 +36,11 @@ services:
     tags:
       - { name: 'event_subscriber' }
 
+  reinstall.migrate.map_save:
+    class: 'Drupal\reinstall\EventSubscriber\IdMapSave'
+    tags:
+      - { name: 'event_subscriber' }
+
   reinstall.migrate.post_row_save:
     class: 'Drupal\reinstall\EventSubscriber\IdPostRowSave'
     tags:

+ 56 - 0
src/EventSubscriber/IdMapSave.php

@@ -0,0 +1,56 @@
+<?php
+
+namespace Drupal\reinstall\EventSubscriber;
+
+use Drupal\Component\Utility\NestedArray;
+use Drupal\migrate\Event\MigrateEvents;
+use Drupal\migrate\Event\MigrateMapSaveEvent;
+use Drupal\migrate\Event\MigratePostRowSaveEvent;
+use Drupal\migrate\Row;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Class IdMapSave normalizes ids right before saving the map.
+ *
+ * This is needed because raw reinstall sources do not flatten source values,
+ * and Sql::saveIdMap() assumes property fields are scalars of the described
+ * type for the source, so we need to overwrite the source value for this last
+ * step.
+ *
+ * Example: a node has an integer "nid" key, but is dumped like:
+ * <nid>:
+ *   nid:
+ *     -
+ *       value: 2
+ *   ...
+ */
+class IdMapSave implements EventSubscriberInterface {
+
+  public static function getSubscribedEvents() {
+    $events = [
+      MigrateEvents::MAP_SAVE => 'onMapSave',
+    ];
+
+    return $events;
+  }
+
+  public function onMapSave(MigrateMapSaveEvent $event) {
+    $rawIdValues = $event->getFields();
+    $filteredIdValues = array_filter($rawIdValues, function ($v) {
+      return true;
+    });
+    foreach ($filteredIdValues as $idName => $idValue) {
+      $current = $idValue;
+      while (is_array($current)) {
+        $current = current($current);
+      }
+      // Unavailable because source is frozen at this point.
+      // $row->setSourceProperty($idName, $current);
+      // So let's use brute force.
+      NestedArray::setValue($row->getSource(), explode(Row::PROPERTY_SEPARATOR, $idName), $current, TRUE);
+    }
+
+    return;
+  }
+
+}

+ 17 - 1
src/Plugin/migrate/source/ReinstallSourceBase.php

@@ -35,6 +35,8 @@ use Symfony\Component\Yaml\Yaml;
 class ReinstallSourceBase extends SourcePluginBase implements ContainerFactoryPluginInterface, ConfigurablePluginInterface {
   use SimpleSourceTrait;
 
+  const INJECTED_ID_PREFIX = '_reinstall_';
+
   /**
    * The event_dispatcher service.
    *
@@ -77,7 +79,7 @@ class ReinstallSourceBase extends SourcePluginBase implements ContainerFactoryPl
     $parsedRecords = $this->initialParse($configuration);
     $this->records = empty($this->configuration['raw'])
       ? array_map([$this, 'flattenRecord'], $parsedRecords)
-      : $parsedRecords;
+      : array_map([$this, 'injectIds'], $parsedRecords);
     $eventDispatcher->dispatch(ReinstallEvents::POST_SOURCE_PARSE, new SourceEvent($this));
   }
 
@@ -172,6 +174,20 @@ class ReinstallSourceBase extends SourcePluginBase implements ContainerFactoryPl
     return $this->iterator;
   }
 
+  protected function injectIds(array $record) {
+    $idKeys = array_keys($this->getIds());
+    foreach ($idKeys as $idKey) {
+      $sourceIdKey = substr($idKey, strlen(static::INJECTED_ID_PREFIX));
+      $current = $record[$sourceIdKey];
+      while (is_array($current)) {
+        $current = current($current);
+      }
+      $record[$idKey] = $current;
+    }
+
+    return $record;
+  }
+
   /**
    * Load then parse the file requested in configuration and return its records.
    *

+ 8 - 0
src/Plugin/migrate/source/SimpleSourceTrait.php

@@ -150,6 +150,14 @@ trait SimpleSourceTrait {
       $ids[$keyName] = ['type' => $idType];
     }
 
+    if (!empty($this->configuration['raw'])) {
+      $keys = array_keys($ids);
+      foreach ($keys as $key) {
+        $ids[ReinstallSourceBase::INJECTED_ID_PREFIX . $key] = $ids[$key];
+        unset($ids[$key]);
+      }
+    };
+
     return $ids;
   }