Bild zeigt Nodz, der die richtigen Nodes miteinander verknüpft.

Overfeeding: Drupals Feeds-Modul ausgereizt - Import von Entity-Referenzen

19.06.14

Daten in Drupal: Während Teil eins den Import mehrsprachiger Daten behandelt, wagen wir uns nun an den Import relationaler Daten.

Datenimport in Drupal: relationale Daten

Im ersten Teil des Artikels über Datenimport in Drupal habe ich erklärt, wie der Import mehrsprachiger Daten funktioniert und gezeigt, wie diese Nodes Nodes beim Import miteinander verknüpft werden können. Im zweiten Teil wird der Fokus auf etwas Ähnlichem liegen: Nun geht es um relationalen Inhalt. Ganz allgemein geht es also um verschiedene Objekte oder Tabellen mit Referenzen zueinander, in Drupal wird dies durch mehrere verschiedene Inhaltstypen mit Entity-Referenzen realisiert.

Relationale Daten zu importieren ist etwas komplizierter als der Import mehrsprachiger Daten; wir werden aber sogar noch einen Schritt weiter gehen: Nachdem ich die Grundlagen des relationalen Imports mit Entity-Referenzen erklärt habe, werde ich zeigen, wie dies mit dem mehrsprachigen Import kombiniert werden kann, sodass wir einen mehrsprachigen relationalen Import durchführen können.

Utensilien: Modul-Stack

Als Basis verwenden wir den gleichen Modul-Stack wie beim ersten Artikel:

Und fügen ein paar weitere zur Liste hinzu:

Entity reference ist hier die Basis, ohne dieses Modul sind keine relationalen Daten realisierbar. Um mit Feeds arbeiten zu können, brauchen wir Feeds Tamper: String to ID, womit wir basierend auf dem Datenimport Nodes nachschlagen können und eine Entity-Referenz setzen können. Views wird für ein erweitertes Setup von Feeds Tamper: String to ID benötigt, sodass wir den Query, der ein Import-Feld einer Node in Drupal zuordnet, anpassen können.

Bei einem noch weiter spezifizierten Setup mit i18n und Entity-Referenzen ist es zudem hilfreich, Internationalization contributions zu verwenden, womit Entity-Referenzen synchronisiert werden können. Es ist zwar für den Import nicht zwingend notwendig, hilft jedoch später beim Editieren der Daten erheblich, um Ordnung zu halten.

Das Wichtigste zuerst: Referenzen Importieren

Das Schwierige ist, die Mappings zwischen den Entities zu definieren. Glücklicherweise konnte ich aus einer anderen Datenbank importieren, und alle meine Entities hatten unique IDs. Statt einer abstrakten Ausführung werde ich nachfolgend ein konkretes Beispiel verwenden. Ich importierte:

  • Reiseangebote (Travel offers)
  • Reisen (Travels)

Reiseangebote repräsentieren ein allgemeines Element mit den geteilten Daten; Reisen repräsentieren eine spezifische Instanz des Reiseangebots mit gewissen Informationen wie beispielsweise einem Datum, die bei einem Element jeweils einzigartig sind. Beide hatten also ein Set von unique IDs, und die Reisen hatten ein Referenzfeld, das die IDs der Reiseangebote, mit denen sie verknüpft waren, enthielt. Was die Implementation in Drupal betrifft, so haben wir zwei Inhaltstypen, von denen der eine eine Referenz zum anderen hat.

Bild zeigt wie die zwei Inhaltstypen verknüpft sind.
Reisen (Travels) haben eine Referenz zu den Reiseangeboten (Travel offers).

Falls keine unique IDs für alle Reiseangebote und Reisen vorhanden sind, so könnten diese jederzeit durch einen Preprocessing-Schritt hinzugefügt werden. Allerdings brauchen wir letzten Endes auch hier eine Referenz von einem Entity-Typ zum anderen, selbst wenn es der Titel-String ist, ansonsten bleibt nichts anderes übrig, als die Daten manuell miteinander zu verknüpfen.

Wichtig ist, dass dieses Referenz-ID-Feld beim Importieren der Parent- und der Child-Entity beibehalten wird, selbst wenn Drupal stattdessen die NID verwenden wird. Andernfalls ist es später nicht möglich, diese nachzuschlagen.

Ich unterteile den Import-Prozess in drei Schritte (wobei ich davon ausgehe, dass die Reiseangebote bereits wie in Teil 1 beschrieben importiert worden sind):

  1. Setup des Node processor Mappings
  2. Setup der Lookup view
  3. Setup des Feeds Tampers

1. Setup der Feeds-Mappings

Mappings können grundsätzlich so gehandhabt werden, wie ich es im ersten Teil des Artikels erklärt habe, mit Ausnahme der Mappings von Entity-Referenzen. Hierfür brauchen wir Feeds Tamper: String to ID. Als Erstes erstellen wir auf der Feed Node Processor Mapping-Seite ein Mapping vom importierten Referenzfeld zum Entity-Referenzfeld des Nodes. In meinem Fall hatte ich:

  • eine Nummer eines Reiseangebots
  • die ich verknüpfen wollte mit einer Parent-Reiseaangebot Entity ID (Entity reference by Entity ID)

Zudem müssen wir den Tamper Convert string into entity ID auf diesem Mapping erstellen, denn wenn das importierte Feld keine Node-ID ist, funktioniert der Import nicht. Je nachdem, was für Referenzen wir importieren, gibt es zwei Optionen:

  • Entweder ist es der tatsächliche Titel des Nodes, den wir referenzieren wollen. In diesem Fall brauchen wir bloss Entityreference autocomplete, wir können bei Schritt 3 weiterfahren (Setup der Feeds Tamper)
  • Oder es ist nicht das Titelfeld. In diesem Fall müssen wir eine View erstellen, die basierend auf dem Referenzfeld eine Node-ID nachschlägt.

2. Setup der Mapping-View

Wenn wir die Tamperseite hinzufügen, erhalten wir Aufschluss über ein paar Dinge:

  • Die View nimmt einen String als ‚Contextual Filter‘-Argument
  • Zeigt ‚Fields‘ an
  • Gibt uns eine Reihe, die einzig eine ID als erste Spalte enthält (nicht verlinkt)

Deswegen müssen wir die View zuerst erstellen. Meine heisst Feeds Travel Linking. Ich wählte weder create page noch create block und selektierte als meinen Inhaltstyp den Reiseangebotstyp. Dies wird eine View mit einem Master-Display erstellen. Meine Settings sind dabei die folgenden:

  • Format
    • Format: Unformatted list
    • Show: Fields
  • Fields:
    • Content: NID (not linked, no label)
  • Filter Criteria:
    • Content: Type (= Reiseangebot) – Diese Einstellung erfolgt automatisch beim Erstellen der View
  • Advanced
    • CONTEXTUAL FILTERS
    • Content: SN_V (Dies war der Name meines Referenzfeldes in den Reiseangeboten)
      • When the filter value is not available: Hide View

Sofern wir eine der Referenzen kennen, können wir nun das Auto-Preview der View verwenden, um das Ganze zu testen: Wenn wir die Nummer eingeben, so sollten wir als Ausgabe wir einzig eine Node ID erhalten. Die Kernpunkte sind, dass wir nur einen Contextual Filter haben und einzig eine unformatierte, unverlinkte Node ID ausgeben.

3. Setup des Tampers

Nun, da wir die View haben, die ausgefüllt werden soll, können wir dem Tamper zuwenden. Dazu wählen wir Convert string into entity ID, dann gibt es drei Einstellungen:

  • Lookup method ⇒ Views
  • Choose the view ⇒ Master (der Feeds Travel Linking View)
  • Choose ID field ⇒ NID

Wenn wir den Import ausführen, wird Tamper nun die Referenz an unsere View weitergeben, die dann im Gegenzug eine Node ID ausgibt. Der Tamper wird daraufhin die Entity-Referenz Node ID mit diesem Wert setzen – und wir haben eine funktionierende Referenz!

Mehrsprachig und relational

Zurück zum Gesamtbild: Ich habe Reiseangebote, die jeweils mit mehreren Reise-Instanzen verknüpft sind. Im ersten Teil des Artikels zeigte ich, wie ein mehrsprachiger Import mit den Reiseangeboten durchgeführt werden kann. Ich habe soeben erklärt, wie Reisen importiert und mit Reiseangeboten verlinkt werden können. Es fehlt uns aber noch ein letzter Teil des Puzzles, denn die Reisen sind natürlich ebenfalls mehrsprachig.

Wir können die Tricks aus Teil 1 erneut anwenden, allerdings ist das Problem damit noch nicht ganz gelöst. Ich implementierte also erneut hook_feeds_after_save()., um die Übersetzungs-ID anzuzeigen, sodass die Nodes mit ihren entsprechenden Übersetzungen verknüpft werden (oder andernfalls als primärer Node gesetzt werden). Danach müssen die Referenzen allerdings ebenfalls lokalisiert werden:

  • Die englischen Reisen sollen zu den englischen Reiseangeboten verweisen
  • Die deutschen Reisen sollen zu den deutschen Reiseangeboten verweisen

Da der Titel in beiden Sprachen unterschiedlich sein kann, können wir nicht einfach auf autocomplete vertrauen, sondern müssen das Setup erweitern. Da wir nur einen Contextual Filter mit Feeds Tamper: String to ID Views haben können, brauchen wir zwei Views, eine, welche die englischen Node IDs nachschlägt und eine, welche die deutschen Node IDs nachschlägt. Angesichts der Tatsache, dass wir bloss eine Feeds Tamper string to ID-View per Feed haben können, brauchen wir zudem auch zwei Feeds. Wir müssen also das vorhergehende Diagramm insofern erweitern, dass es beide Sprachen berücksichtigt.

Bild zeigt wie die zwei Inhaltstypen verknüpft sind unter Einbezug der Übersetzung.
Unter Berücksichtigung beider Sprachen müssen wir unser gesamtes Setup verdoppeln.

Wir können die oben definierte View wiederverwenden und klonen, sodass wir das folgende Setup haben:

  • Feeds Travel Linking EN
    • Different settings:
    • Filter Criteria:
      • Content: Language (= EN)
  • Feeds Travel Linking DE
    • Different settings:
    • Filter Criteria:
      • Content: Language (= DE)

Bild zeigt einen Screenshot des Setups der View.
Die Settings der View.

So wird unser Feeds-Import für die englische Sprache Feeds Travel Linking EN für den Convert string into entity ID-Tamper verwenden während der Feeds-Import für die deutsche Sprache Feeds Travel Linking DE für den entsprechenden Convert string into entity ID verwendet.

Bild zeigt einen Screenshot des Tampers "Convert string into entity ID."
Auswahl der View im Tamper „Convert string into entity ID.“

Fazit

Wir können nur mit Feeds Tamper: String to ID einen Import in zwei Schritten durchzuführen, mit dem wir aus einer externen Quelle verlinkte Nodes in Drupal importieren können. Dazu müssen wir zuerst die Parent-Entities importieren und dann mit einem Schlüsselwert einen Tamper erstellen, um den verlinkten Node beim Import nachzuschlagen und die Entity-Referenz richtig zu setzen.

Einen Schritt weiter gehend können wir selbst wenn die Entity der höchsten Ebene mehrsprachig ist eine verlinkte Entity importieren. Dazu brauchen wir ein etwas komplexeres Setup, um sicherzustellen, dass die importierte Entity zur entsprechenden Übersetzung verlinkt wird und zudem auch eine Entity-Referenz zur richtigen Sprache erstellt wird. So können wir letzten Endes einen mehrsprachigen, relationalen Import realisieren.

Immer noch verwirrt? Hinterlassen Sie einen Kommentar!