Direkt zum Inhalt
29. August 2017

Wie überspringt man eine Zeile, wenn die übergeordnete Entität während einer Drupal 8-Migration nicht existiert?

by Richard Papp

Mit Drupal 8 können Sie inkrementelle Migrationen durchführen und Datensätze aktualisieren, die sich seit der letzten Migration geändert haben. Wenn Sie in der Zwischenzeit solche Datensätze in Drupal 8 löschen, kann eine Migrationsaktualisierung fehlschlagen.

Wir sind auf dieses Problem gestoßen, als wir migrierte Forumsknoten aktualisieren wollten, die in der Zwischenzeit weitere Kommentare auf der Drupal 6 Quellseite erhalten hatten. Deren übergeordneter Knoten existierte in Drupal 8 nicht mehr:

TypeError: Argument 1 übergeben an Drupal\forum\ForumIndexStorage::updateIndex()
muss das Interface Drupal\node\NodeInterface implementieren, null gegeben,
aufgerufen in /core/modules/forum/forum.module
in Zeile 272 in Drupal\forum\ForumIndexStorage->updateIndex()
(Zeile 92 von /core/modules/forum/src/ForumIndexStorage.php)
#0 /core/modules/forum/forum.module(272):
Drupal\forum\ForumIndexStorage->updateIndex(NULL)

Um solche Fehler zu vermeiden, haben wir das Prozess-Plugin skip_row_if_not_exist geschrieben. Sie können den Entitätstyp und die Eigenschaft, auf die geprüft werden soll, sowie eine Migrationsmeldung konfigurieren:

<?php

namespace Drupal\migrate_custom\Plugin\migrate\process;

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

/**
 * Überspringt die Verarbeitung der aktuellen Zeile, wenn ein Zielwert nicht vorhanden ist.
 *
 * Das Prozess-Plugin skip_row_if_not_exist prüft, ob ein Wert vorhanden ist. Wenn der
 * Wert existiert, wird er zurückgegeben. Andernfalls wird eine MigrateSkipRowException
 * geworfen.
 *
 * Verfügbare Konfigurationsschlüssel:
 * - Entität: Die Zielentität, nach der gesucht werden soll.
 * - Eigenschaft: Die zu prüfende Eigenschaft der Zielentität.
 * - message: (optional) Eine Nachricht, die in der Tabelle {migrate_message_*}
 * für diese Zeile protokolliert werden soll. Wenn nichts angegeben wird, wird nichts in der Nachrichtentabelle protokolliert.
 *
 * Beispiel:
 * Kommentare für migrierte Knoten, die am Zielort nicht mehr existieren, nicht importieren.
 * Ziel existieren.
 *
 * @code
 * process:
 * entity_id:
 * -
 * Plugin: migration_lookup
 * Migration:
 * - d6_node
 * Quelle: nid
 * -
 * # Prüfen, ob ein Knoten in der Zieldatenbank existiert.
 * plugin: skip_row_if_not_exist
 * Entität: node
 * Eigenschaft: nid
 * message: 'Kommentierte Entität nicht gefunden.'
 * @endcode
 *
 * Dies gibt die Knoten-ID zurück, wenn sie existiert. Andernfalls wird die Zeile
 * uebersprungen und die Nachricht "Kommentierte Entitaet nicht gefunden." wird in der
 * Nachrichtentabelle protokolliert.
 *
 * @see \Drupal\migrate\Plugin\MigrateProcessInterface
 *
 * @MigrateProcessPlugin(
 * id = "skip_row_if_not_exist",
 * handle_multiples = TRUE
 * )
 */
class SkipRowIfNotExist extends ProcessPluginBase {

  protected $entity = 'Knoten';
  protected $property = 'nid';
  
  function __construct($configuration, $plugin_id, $plugin_definition) {
    Elternteil::__construct($konfiguration, $plugin_id, $plugin_definition);

    if (!empty($configuration['entity'])) {
      $this->entity = $configuration['entity'];
    }

    if (!empty($configuration['property'])) {
      $this->Eigenschaft = $Konfiguration['Eigenschaft'];
    }
  }

  /**
   * {@inheritdoc}
   */
  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    $count = \Drupal::entityQuery($this->entity)
      ->condition($this->property, $value)
      ->accessCheck(FALSE)
      ->count()
      ->execute();

    if (!$count) {
      $message = isset($this->configuration['message']) ? $this->configuration['message'] : '';
      throw new MigrateSkipRowException($message);
    }

    return $value;
  }

}

Beispiel

Um zu prüfen, ob der übergeordnete Knoten eines Kommentars existiert, würde man folgendes tun:

  1. Kopieren Sie /core/modules/comment/migration_templates/d6_comment.yml in ein eigenes Migrationsmodul.
  2. Ersetzen Sie entity_id: nid durch zwei Prozess-Plugins.
    1. Suchen Sie die Ziel-Nid des übergeordneten Knotens in der Migrations-Zuordnungstabelle
    2. Überspringe die ganze Zeile, wenn der Knoten nicht existiert

Vor (Auszug)

process:
  # Wenn Sie diese Datei verwenden, um eine benutzerdefinierte Migration zu erstellen, sollten Sie das
  # das Feld cid entfernen, um inkrementelle Migrationen zu ermöglichen.
  cid: cid
  pid:
    plugin: migration_lookup
    Migration: d6_Kommentar
    Quelle: pid
  Entity_id: nid

Nachher (Auszug)

process:
  # Wenn Sie diese Datei verwenden, um eine benutzerdefinierte Migration zu erstellen, sollten Sie das
  # das Feld cid entfernen, um inkrementelle Migrationen zu ermöglichen.
  cid: cid
  pid:
    plugin: migration_lookup
    Migration: d6_Kommentar
    Quelle: pid
  Entitäts_id:
    -
      Plugin: Migration_Ansicht
      Migration:
        - d6_node
      Quelle: nid
    -
      plugin: skip_row_if_not_exist
      Entität: node
      Eigenschaft: nid
      Meldung: 'Kommentierte Entität nicht gefunden.'

 

Tools
Services

Neuen Kommentar hinzufügen

Klartext

  • Keine HTML-Tags erlaubt.
  • Zeilenumbrüche und Absätze werden automatisch erzeugt.
  • Website- und E-Mail-Adressen werden automatisch in Links umgewandelt.
CAPTCHA
Diese Sicherheitsfrage überprüft, ob Sie ein menschlicher Besucher sind und verhindert automatisches Spamming.