Löschbar oder nicht, das ist hier die Frage

Wir befinden uns im Jahre 10 nach Drupal und ganz Core ist von veränderbaren Hooks besetzt. Ganz Core? Nein! Ein von unbeugsamen Funktionen bevölkerter Teil der Node API hört nicht auf, dem Kätzchen liebenden  Entwickler Widerstand zu leisten. Aber der Reihe nach.

In einem aktuellen Projekt gibt es die Notwendigkeit, Beiträge nur durch einige berechtigte Benutzer löschen zu lassen. Das ist soweit kein Problem, da Drupal auf Inhaltstyp-Ebene die Rechte zum Erstellen / Bearbeiten und Löschen fein einstellbar macht. Die Anforderungen gehen aber noch weiter, denn ein Beitrag darf nur dann gelöscht werden, wenn andere per PHP abfragbare Umstände zutreffen. In dem konkreten Fall soll per SOAP eine andere Seite nach einem Status abgefragt werden. Ist dieser Status negativ, soll das Löschen verhindert werden.

Die Node API von Drupal 7 bietet viele Hooks um den Lebenszyklus einer Node zu beeinflussen. Auch für das Löschen eines Beitrags gibt es einen hook: hook_node_delete(). Leider greift dieser hook erst nachdem ein Beitrag gelöscht wurde. Vor dem Löschen eines Beitrags wird im Core kein Hook eingefügt um den Prozess rechtzeitig abbrechen zu können. Aber Drupal wäre nicht Drupal, wenn diese Funktion nicht nachzubauen wäre.

hook_predelete_node()

Für diesen Zweck habe ich das Modul predelete für Drupal 7 gebastelt. Es biegt die normale Löschfunktion per menu_alter auf einen eigenen Menuhandler um und gibt dort anderen Modulen die Möglichkeit, auf den anstehenden Löschvorgang zu reagieren. Da Nodes nicht nur über den Menüeintrag gelöscht werden können, sondern z.B. auch über den Administrationsbereich, hakt sich das Modul zusätzlich in das Formular zur Bestätigung der zu löschenden Beiträge ein. Hier wird ebenfalls über hook_predelete_node abgefragt, ob das Löschen erlaubt ist und der Beitrag andernfalls aus dem Formular entfernt.

Den hook nutzen

Der hook kann nun einfach implementiert werden und soll ein Array in folgendem Format zurückgeben:

<?php return array( 'result' => FALSE, // TRUE oder FALSE 'reason' => 'Ein Grund warum nicht oder eben doch', ); ?>

Einsatzzwecke für das Modul gibt es viele. So könnte man nach 20 Uhr verhindern, dass Beiträge gelöscht werden. Oder es dürfen keine Beiträge gelöscht werden, die älter als 1 Jahr sind. Oder es wird ein Checkbox-Feld an dem Inhaltstyp angelegt, das über die Zugriffsberechtigungen nur bestimmten Leuten zugänglich ist und kontrolliert, ob der Beitrag gelöscht werden darf. Genau so ein Beispiel ist mit in dem Modul enthalten.

Um zu demonstrieren wie einfach die Implementierung ist. hier ein funktionierendes Beispiel. Einfach die folgenden 12 Zeilen Code in ein eigenes Modul save_nid10.module speichern und die Node mit der ID 10 darf nie gelöscht werden:

<?php /** * Implements hook_predelete_node(). */ function save_nid10_predelete_node($node) { $result = $node->nid == 10 ? FALSE : TRUE; $reason = $node->nid == 10 ? t('The node with the id 10 is magically shielded and may not be deleted.') : t('Deletion is ok.'); return array( 'result' => $result, 'reason' => $reason ); } ?>

(foto stigwaage via flickr.com CC BY-NC 2.0)

(edit: Die API verlangt in Version 7.x-1.1 jetzt das node Objekt und nicht mehr nur die Node id.)