Drupal Daten als CSV exportieren (am Beispiel "Google Merchant Center Export für Drupal Commerce")

Wer seinen Drupal Commerce Shop an Google Merchant Center anbinden möchte, kann dafür einfach das bestehende Modul nutzen. Allerdings ist das Modul ziemlich fest an die vorgegebene Struktur und den Aufbau von Drupal Commerce gebunden. Wer das Shop Modul in Drupal etwas weniger umfangreich nutzt, der kann sich auch einfach und schnell seine Shop-Daten als CSV-Datei ausgeben lassen und manuell in Google Merchant Center einbinden. Notwendig dafür sind nur wenige Funktionen in einem eigenen Modul.

Als erstes implementieren wir hook_menu() um einen aufrufbaren Pfad für den Dateiexport bereitzustellen. Dieser wird dann später in Google Merchant Center für den automatischen Abruf eingerichtet:

function MYMODULE_cartpreview_menu() {

  $items['googlemerchantexport/%'] = array(

    //Hier wird definiert, welche Funktion bei Aufruf des Pfades getriggert werden soll
    'page callback' => 'MYMODULE_export_googlemerchantcsv',

    //Und hier wird definiert, welcher Teil des Pfades als Parameter an o.g. Funktion übergeben wird
    'page arguments' => array(1),

    //Hier wird definiert, wer Zugriff haben soll (in diesem Fall jeder, der auch den restlichen Seiteninhalt sehen darf... also jeder.
    'access arguments' => array('access content'),

    //Und hier wird definiert, dass die Rückgabe dieses Pfades nicht gecached werden soll. Sinn eines automatischen Abrufs ist ja, dass die Daten immer aktuell übergeben werden
    'cache' => DRUPAL_NO_CACHE,

  );

  return $items;
}

Mit voller Absicht enthält der Pfad Platz für einen Parameter, damit wir das Kürzel für die Sprache übergeben können, die für den Export genutzt werden soll.

Jetzt brauchen wir eine Funktion, die uns aus einem Array eine CSV-Datei erstellt und zurückgibt.

function MYMODULE_array_to_csv_download($array, $filename = "export.csv", $delimiter=";", $return = FALSE) {

  //Wenn als Parameter $return = TRUE gesetzt wird, wird die Datei mit ihrem Inhalt zurückgegeben
  if($return) {

    $time = time();
    $filepath = 'private://' . $time . '.csv';
    $f = fopen($filepath, 'w');

    foreach ($array as $line) {
      fputcsv($f, $line, $delimiter);
    }

    fclose($f);

    return $filepath;

  }
  //Wenn als Parameter $return = FALSE gesetzt wird, wird die Datei ausgegeben, d.h. der Browser wird sie downloaden
  else {

    //Damit der Datenstream richtig zugeordnet werden kann, wird als Header application/csv und der gewünschte Dateiname übergeben
    header('Content-Type: application/csv');
    header('Content-Disposition: attachement; filename="'.$filename.'";');

    //mit fopen wird eine temporäre Datei erzeugt und der Zeiger zum schreiben gesetzt
    $f = fopen('php://output', 'w');

    //$array enthält die Daten, die in die CSV geschrieben werden sollen und wird ab hier durchlaufen
    foreach ($array as $line) {

      //fputcsv schreibt in die Datei $f die Zeile $line und trennt die einzelnen Werte mit $delimiter
      fputcsv($f, $line, $delimiter);

    }
  }
} 

Was jetzt noch fehlt ist eine Funktion MYMODULE_export_googlemerchantcsv() die bei Aufruf des oben erzeugten Pfades durchlaufen wird und an irgendeiner Stelle MYMODULE_array_to_csv_download() aufruft. Aus dem folgenden Code wird auch deutlich, wie das Array aufgebaut sein muss, das an die CSV-Export-Funktion übergeben werden muss.

function MYMODULE_export_googlemerchantcsv($lang, $return = FALSE) {

  //Per EntityFieldQuery werden alle Drupal Commerce Produkte ausgelesen
  $query = new EntityFieldQuery;

  $productqry = $query
    ->entityCondition('entity_type', 'commerce_product')
    ->entityCondition('bundle', array('myproducttype'))
    ->propertyCondition('status', 1) //nur veröffentlichte Produkte einbeziehen
    ->execute();

  $product_items = entity_load('commerce_product', array_keys($productqry['commerce_product']));

  //Array für die Ausgabe initialisieren
  $csvoutput = array();

  //Die erste Zeile der CSV-Datei enthält die Überschriften (in diesem Fall aus der Google Merchant Center Spezifikation entnommen)
  $csvoutput[] = array(
    'brand',
    'title',
    'id',
    'mpn',
    'price',
    'currency',
    'image_link',
    'link',
    'condition',
    'availability',
    'gtin',
    'description',
    'google_product_category',
    'product_type',
  );

  //Alle folgenden Zeilen enthalten die zugehörigen Produktdaten. Diese können aus Properties bestehen, aber auch aus selbst hinzugefügten Feldern

  //Hier kann der Parameter $lang genutzt werden um anstelle von LANGUAGE_NONE die sprachsensitiven Felder in der jeweilig vorliegenden Übersetzung auszugeben.
  foreach($product_items as $key => $value) {

    $csvoutput[] = array(

      'MyBrand', //Brand

      $value->title_field[$lang][0]['value'], //Title

      $value->product_id, //ID

      $value->sku, //MPN

      number_format($value->commerce_price[LANGUAGE_NONE][0]['amount']/100, 2, ",", "."), //Price

      $value->commerce_price[LANGUAGE_NONE][0]['currency_code'], //Currency

      file_create_url($value->field_image[LANGUAGE_NONE][0]['uri']), //Image

      url('products/' . taxonomy_term_load($value->field_category[LANGUAGE_NONE][0]['tid'])->name . '/' . $value->sku, array('absolute' => TRUE)), //Link

      'new', //Condition

      'in stock', //Availability

      $value->field_gtin[LANGUAGE_NONE][0]['value'], //Gtin

      $value->field_summary[$lang][0]['value'], //Description

      "Baby & Kleinkind	> Babysicherheit > Babysicherungen & Schutzvorrichtungen", //Google Product Category

      taxonomy_term_load($value->field_category[LANGUAGE_NONE][0]['tid'])->name, //Product Type

    );
  }

  //Jetzt besitzen wir eine Matrix, also ein Array das im Schlüssel 0 ein weiteres Array mit Überschriften und in den Schlüsseln 1 - n Arrays mit den Produktdaten enthält

  //Wenn eine Rückgabe an die aufrufende Funktion gewünscht ist, dann rufen wir die CSV-Export-Funktion mit dem Parameter $return = TRUE auf und returnieren das Ergebnis ebenfalls sofort wieder.
  if($return) {

    return MYMODULE_cartpreview_array_to_csv_download($csvoutput, 'gm_export.txt', "\t", $return);

  }

  //Wenn keine Rückgabe, sondern eine Ausgabe gewünscht ist, reicht es die CSV-Export-Funktion einfach nur auszuwerfen. Diese wird dann die nötigen header setzen und für den Download sorgen.
  else {

    MYMODULE_cartpreview_array_to_csv_download($csvoutput, 'gm_export.txt', "\t", $return);
    return NULL;

  }
}

Und das war's auch schon. Selbstredend kann die Funktion MYMODULE_array_to_csv_download() auch für andere Export-Zwecke genutzt werden und könnte dementsprechend Teil einer eigenen API werden, die von vielen verschiedenen Modulen genutzt werden kann.