Ein eigenes API Modul für Drupal schreiben

So schön es auch ist, Webanwendungen mit Drupal 7 zu entwickeln, gibt es trotzdem immer wieder Anwendungsfälle wo einfach ein paar Funktionen fehlen. Das liegt daran, dass ein Framework wie Drupal natürlich generische Methoden zur Verfügung stellen muss, um alle denkbaren Anwendungsfälle möglich zu machen. Oft gibt es für einen Entwickler aber aufgrund der Sache an der er Arbeit immer nur einen identischen Anwendungsfall den er immer und immer wieder ausführen muss. Was gäbe es da sinnvolleres zu tun, als ein eigenes API-Modul zu schreiben, in dem diese zahlreichen Befehle gebündelt und schneller nutzbar gemacht werden.

Beispiel: Programmatisch eine Node erstellen.

Im Prinzip ganz einfach, aber es sind ein paar Zeilen Code dafür notwendig. Wer also auf seiner Seite oft programmatisch neue Nodes erstellt, für den macht eine entsprechende API-Funktion Sinn. Hier ein Vorschlag:

 /**
 * Method for creating new node objects.
 *
 * @param $type
 * 		The content type of the node
 *
 * @param $title
 *		The node title
 *
 * @param $lang
 *		The language of the node
 *
 * @param $author
 *		The author of the node
 *
 * @param $status
 *		The publishing status of the node
 *
 * @param $sticky
 *		The sticky option of the node
 *
 * @param $promote
 *		The promote option of the node
 *
 * @return object
 */
function my_api_create_new_node($type = '', $title = '', $lang = '', $author = 0, $status = 0, $sticky = 0, $promote = 0) {
	//Define new node
	$new_node = new stdClass();
	$new_node->type = $type;
	$new_node->is_new = TRUE;
	
	//Store title
	$new_node->title = $title;
	
	//Prepare object
	node_object_prepare($new_node);
	
	//Define language
	$new_node->language = $lang;
	
	//Define as guest content
	$new_node->uid = $author;
	
	//Store states
	$new_node->status = $status;
	$new_node->sticky = $sticky;
	$new_node->promote = $promote;
	
	//Submit and save node
	$new_node = node_submit($new_node);
	node_save($new_node);
	
	return $new_node;
}

So geht's ganz einfach. Zurückgegeben wird ein frisches Node-Objekt, dessen Felder man jetzt nach belieben befüllen kann. Damit spart man sich eine ganze Menge Zeit und unnötig doppelten Code.

Beispiel: Eine CSV-Datei ausgeben

Hin und wieder braucht man mal einen Export. Bevor man jetzt unnötigerweise ein Modul wie Views Data Export installiert, kann man das auch einfach mit einer kleinen Funktion lösen.

/**
 * Method for creating csv files.
 *
 * @param $array
 * 		A multidimensional array. For each line the array contains another
 *		array with the items in the order they are supposed to be output
 *
 * @param $filename
 *		The name of the file
 *
 * @param $delimiter
 *		The delimiter for the csv items
 *
 * @param $return
 *		Whether the file should be output with the given filename or returned as a file object
 *
 * @return string
 */
function my_api_array_to_csv_download($array, $filename = "export.csv", $delimiter=";", $return = FALSE) {
	if($return) {
		$time = time();
		$filepath = 'private://' . $time . '.csv';
		$f = fopen($filepath, 'w');
		foreach ($array as $line) {
			fputcsv($f, $line, $delimiter);
		}
		fclose($f);
		return $filepath;
	}
	else {
		header('Content-Type: application/csv');
		header('Content-Disposition: attachement; filename="'.$filename.'";');
		$f = fopen('php://output', 'w');
		foreach ($array as $line) {
			fputcsv($f, $line, $delimiter);
		}
	}
}

Und schon hat man ein Werkzeug zur Hand um ganz schnell mehrdimensionale Arrays in CSV zu verwandeln. Und damit nicht genug, die Funktion unterstützt über den $return-Parameter sogar die Option, die Datei nicht direkt auszugeben, sondern als Dateiobjekt zurückzugeben, so dass man diese irgendwo speichern kann.

Und so weiter. Anwendungsfälle gibt es genug. Zum Beispiel ist es bei der Arbeit mit Field Collections immer mit ein paar unnötigen Zeilen verbunden, einzelne Field Collection Items zu löschen oder komplett neue Field Collection Items zu erstellen. Das geht deutlich schneller mit einer kleinen Funktion, die den für dich typischen Anwendungsfall erledigt. Oder die hochgradig sinnvolle Funktion ctools_field_invoke_field() mit der man Field API Widgets einem selbsterstellten Formular hinzufügen kann. Die Anwendung dieser Funktion benötigt ein paar Vorbereitungen (Feld-Instanz laden, #parents setzen, Feld-Sprache definieren, fields.inc Datei inkludieren, alles an das Form-Array koppeln). Braucht man die Funktion oft (z.B. weil man seine Erstellen- und Bearbeiten-Formulare von Nodes selber baut um diese besser stylen zu können), ist eine kleine API-Funktion, die alle diese Schritte erledigt, hochgradig sinnvoll.

So ein Modul kann vom Entwickler erstellt werden und mit diesem leben und sich weiterentwickeln. Am Anfang jeder Drupal-Installation sollte immer zuerst das eigene API-Modul installiert werden. Wer bei einem riesigen API-Modul Angst vor zuviel Code und Performance-Einbußen hat, der kann seine API-Funktionen natürlich auch in *.inc Dateien unterbringen und diese vor jeder Anwendung inkludieren, z.B. über module_load_include().