Schreiben von actions (Aktionen)
Aktionen in Drupal können am besten mit einer geeigneten Definition verstanden werden.
Für Drupal Seitenadministratoren: Aktionen sind individuelle "Dinge, die Drupal tun kann". Einige Beispiele für Aktionen sind das Versenden von EMails, eine node zu veröffentlichen, einen Nutzer zu sperren oder eine node auf der Startseite der Homepage zu platzieren. Üblicherweise wirst Du Aktionen auf den Konfigurationsseiten von Drupal antreffen.
Für Entwickler: eine Aktion ist eine Funktion die ähnlich einer gespeicherten Prozedur ("sotered procedure") arbeitet. Die Funktionsparameter, so denn welche vorhanden sind, sind in der Datenbank gespeichert und die Funktion wird ausgeführt, indem diese gespeicherten Parameter ermittelt und die Funktion aufgerufen wird.
Kannst Du ein Beispiel für den sinnvollen Einsatz von Aktionen nennen?
Aktionen werden üblicherweise dazu verwendet, die Antwort von Drupal auf ein bestimmtes Ereignis zu konfigurieren. Nehmen wir beispielsweise mal an, ein Seitenadministrator will per EMail benachrichtigt werden, sobald sich ein neuer Benutzer auf der Seite registriert. Er wird also eine "Sende EMail" Aktion konfigurieren und dann das Trigger-Modul dazu verwenden, diese Aktion auszuführen, sobald sich ein Nutzer registriert. (Von der technischen Seite her gesehen, geschieht dies, wenn im Nutzer-Hook die Operation 'insert' abläuft.)
Wo liegt der Quelltext von Aktionen?
Die Engine von Aktionen, die also die Aktionen ausführt, liegt in includes/actions.inc. Der Dispatcher für Aktionen befindet sich in modules/trigger.module.
Die Konfigurationsseiten zum Hinzufügen, Entfernen und Konfigurieren individueller Aktionen sind Teil des system.module.
Die Oberfläche zum Zuweisen von Aktionen zu Ereignissen (sprich hooks) wird durch modules/trigger.module bereitgestellt.
Der hook, der Aktionen beschriebt (hook_actions_info()
) und die Aktionen ansich befinden sich in den individuellen Modulen. Aktionen, die nodes betreffen, wie z.B. "node veröffentlichen" befinden sich in node.module.
Beschreibung einer Aktion mittels hook_action_info()
Lass uns einen Blick auf die Implementierung von hook_action_info()
im User Modul werfen:
<?php
/**
* Implementation of hook_action_info().
*/
function user_action_info() {
return array(
'user_block_user_action' => array(
'description' => t('Block current user'),
'type' => 'user',
'configurable' => FALSE,
'hooks' => array(
'nodeapi' => array('presave', 'delete', 'insert', 'update', 'view'),
'comment' => array('view', 'insert', 'update', 'delete'),
'user' => array('logout'),
),
),
'user_block_ip_action' => array(
'description' => t('Ban IP address of current user'),
'type' => 'user',
'configurable' => FALSE,
'hooks' => array(
'nodeapi' => array('presave', 'delete', 'insert', 'update', 'view'),
'comment' => array('view', 'insert', 'update', 'delete'),
'user' => array('logout'),
)
),
);
}
?>
hook_action_info() muss ein Array zurückgeben, bei dem die Schlüssel die Funktionsnamen der Aktionen sind, die beschrieben werden. Im user.module werden zwei Aktionen beschrieben. Wir betrachten hier nur die Erste. Der Arrayschlüssel der ersten Aktion ist 'user_block_user_action'. Das ist der Name der Funktion die ausgeführt wird, wenn die Aktion läuft. Der Name der Funktion ist nach der folgenden Regel zusammengesetzt:
Modulname + Beschreibung was die Funktion tut + '_action'
In diesem Fall ist das
user + block user + action
was zu 'user_block_user_action' führt.
Als nächstes geben wir im Array ein paar Informationen unter Verwendung der folgenden Schlüssel:
description: eine leicht verständliche Beschreibung zur Aktion (was sie macht)
type: der Typ wird durch das Objekt, auf das die Aktion ausgeführt wird, ermittelt. Möglich sind node, user, comment und system. Oder ein selbst definierter Typ.
configurable: TRUE
oder FALSE
. Dies bestimmt die Oberfläche die Drupal bei der Konfiguration von Aktionen verwendet. Wenn FALSE
gesetzt wird, haben wir den einfachsten Fall, bei dem es keine Oberfläche zur Konfiguration der Aktion gibt. In unserem Beispiel benötigt die Aktion "Block current user" keine weiteren Angaben, da Drupal den aktuellen Nutzer leicht selbst zur Laufzeit ermitteln kann. Eine kompliziertere Aktion, wie beispielsweise "EMail senden", benötigt noch zusätzliche Informationen, wohin die EMail gesendet werden soll, was im Betreff und im Nachrichtentext stehen soll, usw.
hooks: das ist ein Array mit all den Operationen, zu denen die Aktion gehört. Als Schlüssel dient hier der Name des hooks. Das Modul action verwendet dies, um unbenötigte Aktionen herauszufiltern, wenn die Oberfläche zum Zuweisen von Aktionen zu Ereignissen angezeigt wird. Die Aktion "Block current user" definiert beispielsweise die Operation 'logout' des 'user' hook, jedoch nicht die 'login' Operation. Das ist so, weil es ziemlich seltsam wäre, einen Nutzer gleich nach der Anmeldung zu sperren. Es sollte jedoch erwähnt werden, dass dies nur die Anzeigen von Aktionen betrifft; bei der Ausführung von Aktionen hat diese Filterung keinen Effekt. Hinweis: wenn Du Aktionen in Deinem Modul schreibst und alle möglichen hooks unterstützen möchtest, setzte 'hooks' => array('any' => TRUE).
Eine Aktion schreiben
Jetzt, wo wir die Aktion beschrieben haben, können wir den Quelltext schreiben der abläuft, sobald die Aktion ausgeführt wird. Schauen wir auf den Quelltext der Aktion "Block current user":
<?php
/**
* Implementation of a Drupal action.
* Blocks the current user.
*/
function user_block_user_action(&$object, $context = array()) {
if (isset($object->uid)) {
$uid = $object->uid;
}
elseif (isset($context['uid'])) {
$uid = $context['uid'];
}
else {
global $user;
$uid = $user->uid;
}
db_query("UPDATE {users} SET status = 0 WHERE uid = %d", $uid);
sess_destroy_uid($uid);
watchdog('action', 'Blocked user %name.', array('%name' => check_plain($user->name)));
}
?>
Betrachten wir zuerst die Signatur der Funktion für diese Aktion. Es werden zwei Parameter übergeben, ein Objekt und ein Array.
$object: dies ist das Objekt auf das die Aktion erwartet, ausgeführt zu werden. Es stimmt mit dem Typ ('type') überein, der in hook_action_info()
dieser Aktion deklariert wurde. Z.B., wenn der Typ 'user' angegeben wurde, wird hier ein user Objekt übergeben.
$context: dies ist ein Array, welches zusätzliche Informationen enthält. Diese Informationen können für die Aktion hilfreich sein, um den Kontext unter dem sie gerade läuft zu bestimmen. Z.B., das Modul actions setzt die Schlüssel 'hook' und 'op' im Array $context
(z.B. 'nodeapi' als 'hook' und 'insert' als 'op'), so dass die Aktion wenn nötig diverse Entscheidungen anhand dieser Informationen treffen kann..
Als nächstes betrachten wir die Aktion ansich. Sie hat zwei Teile. Im ersten Teil ermittelt sie den zu sperrenden Nutzer, indem sie sich das übergebene Nutzerobjekt ansieht; wenn das fehlschlägt, schaut sie in $context
nach der uid. Wenn das ebenfalls fehlschlägt, nutzt die Aktion das globale Objekt $user
um die zu sperrende uid selbst zu ermitteln. Jetzt werden manchen sich sicherlich darüber wundern. Warum diese vielen Fangnetze? Warum nicht die Übergabe des "richtigen" Parameters erzwingen?
Die Antwort ist nicht eindeutig. Erstens sollen Aktionen eine universelle Funktionssignatur haben, so dass die darunterliegende Engine weniger Arbeit zu verrichten hat und die Performance besser wird.
Zweitens, nimm mal an, Du möchtest 50 Nutzer sperren. Für jeden Nutzer ein komplettes user_load()
auszuführen, nur um ein Objekt zu bekommen, dass an die Aktion übergeben werden kann ist nicht gerade performant, wenn man stattdessen einfach die uid im Array $context
übergeben kann.
Der zweite Teil der Aktion ist derjenige, in dem der Nutzer gesperrt und ein Log-Eintrag geschrieben wird.
Jetzt weisst Du, wie man eine nicht-konfigurierbare Aktion erstellt. Eine konfigurierbare Aktion muss zusätzlich Formular-Handler bereitstellen. Diese Handler ermöglichen es dem Administrator, die gespeicherten Parameter der Aktion zu setzen. Für ein Beispiel schau Dir die Aktion "Unpublish comment containing keyword(s)" im comment.module an.
Dabei speziell die Funktionen comment_unpublish_by_keyword_action_form()
, comment_unpublish_by_keyword_action_submit()
, and comment_unpublish_by_keyword_action()
.
Ich habe ein Modul geschrieben, das hooks zur Verfügung stellt. Wie kann ich Aktionen an diese hooks binden?
Verwende hook_hook_info()
um Deine hooks für Drupal zu beschreiben. Diese hooks verbinden hook-op Kombinationen mit leicht zu lesenden Beschreibungen. Siehe node_hook_info()
oder user_hook_info()
für Beispiele.
Ich will eine Aktion ausführen, will jedoch nicht das actions.module verwenden.
Ok. Du kannst die Aktion direkt aus dem Quelltext heraus mittels der Funktion actions_do() aufrufen. Die Funktion liegt in includes/actions.inc.
- Anmelden oder Registrieren um Kommentare zu schreiben
Hi, welchen Vorteil haben
am 12.10.2011 - 19:26 Uhr
Hi,
welchen Vorteil haben Actions gegenüber einfachen Funktionen, die man über hook_menu(); aufruft?
Aktionen
am 13.10.2011 - 07:21 Uhr
welchen Vorteil haben Actions gegenüber einfachen Funktionen, die man über hook_menu(); aufruft?
In [api:hook_menu] definierte Funktionen werden aufgerufen, wenn der dazugehörige Pfad über einen Browser aufgerufen wird. Aktionen werden ausgeführt, wenn bestimmte Ereignisse auftreten (z.B. ein VBO-Formular abgesendet wird, ein Beitrag erstellt wird, ...). Aktionen sind mit Rules vergleichbar (eigentlich andersrum).