Form API Drupal 7: Erstellen von Formularen in Drupal
In den vorherigen Lektionen haben wir uns mit den Hooks hook_block_info(), hook_block_view(), hook_menu(), hook_permission() vertraut gemacht und können nun beliebig viele Seiten und Blöcke programmatisch erstellen. In dieser Lektion lernen wir das Form API von Drupal 7 kennen, um Formulare zu erstellen. Wir erstellen ein Formular zur Administration der Modulfunktionen und versuchen, möglichst viele bereits bekannte Hooks zu verwenden, um die Fähigkeiten zu festigen.
Zu Beginn geben wir 3 Blöcke aus, das sollte für euch kein Problem sein.
function sitemade_block_info(){
$blocks = array(); // leeres Array initialisieren
$blocks[1]['info'] = 'Benutzerliste'; // Blocktitel für das Admin-Interface
$blocks[2]['info'] = 'Nodeliste';
$blocks[3]['info'] = 'Terminliste';
return $blocks; // Liste der Blöcke zurückgeben
}
function sitemade_block_view($delta = ''){
$block = array(); // leeres Block-Array initialisieren
switch ($delta){
case 1: // delta wie in hook_block_info() definiert
$block['subject'] = 'Benutzer'; // Blocktitel ausgeben
$block['content'] = ''; // leere Stringvariable initialisieren
$query = db_select('users', 'u') // Auswahlabfrage für Benutzer
->fields('u', array('uid', 'name')) // Felder auswählen
->orderBy('u.uid', 'DESC') // absteigend sortieren
->range(0, 5) // fünf Benutzer auswählen
->execute(); // DB-Abfrage ausführen
$users = $query->fetchAll(PDO::FETCH_ASSOC); // Ergebnis als Array holen
foreach($users as $user){
$block['content'] .= '<div><a href="' . base_path() . 'user/' . $user['uid'] . '">' . $user['name'] . '</a></div>';
// base_path() gibt den Pfad zur Seitenwurzel zurück
}
break;
case 2:
$block['subject'] = 'Nodes'; // Blocktitel ausgeben
$block['content'] = '';
$query = db_select('node', 'n')
->fields('n', array('nid', 'title'))
->orderBy('n.nid', 'DESC')
->range(0, 10)
->execute();
$nodes = $query->fetchAll(PDO::FETCH_ASSOC);
foreach($nodes as $node){
$block['content'] .= '<div><a href="' . base_path() . 'node/' . $node['nid'] . '">' . $node['title'] . '</a></div>';
}
break;
case 3:
$block['subject'] = 'Termine'; // Blocktitel ausgeben
$block['content'] = '';
$query = db_select('taxonomy_term_data', 't')
->fields('t', array('tid', 'name'))
->orderBy('t.tid', 'DESC')
->range(0, 10)
->execute();
$terms = $query->fetchAll(PDO::FETCH_ASSOC);
foreach($terms as $term){
$block['content'] .= '<div><a href="' . base_path() . 'taxonomy/term/' . $term['tid'] . '">' . $term['name'] . '</a></div>';
}
break;
}
return $block;
}
Cache leeren, damit die neuen Blöcke im Admin-Bereich erscheinen. Die Blöcke im linken Sidebar ausgeben:

Nun erstellen wir eine Admin-Seite, auf der später das Verwaltungsformular für diese drei Blöcke liegen wird:
function sitemade_permission(){
return array(
'admin content blocks' => array(
'title' => t('Admin content blocks'),
'description' => t('Nodes, Users, Terms'),
),
);
}
function sitemade_menu(){
$items = array(); // Array für Menüeinträge initialisieren
$items['admin/config/content/content_blocks'] = array(
'title' => 'Benutzer-, Node- und Termblöcke',
'description' => 'Blockverwaltung',
'page callback' => '_sitemade_content_blocks',
'access arguments' => array('admin content blocks'),
);
return $items; // Liste der Seiten zurückgeben
}
function _sitemade_content_blocks(){
$content = 'Lorem ipsum!';
return $content;
}
Die Seite wurde erstellt, es sollte nun eine Platzhalter-Seite unter admin/config/content/content_blocks erscheinen:

Als nächstes setzen wir die Berechtigungen für Administratoren zum Zugriff auf diese Seite (dazu haben wir hook_permission() hinzugefügt).

Nun ändern wir den Code der Hooks. Zunächst erstellen wir ein Administrationsformular. Was wollen wir in diesen drei Blöcken verwalten? Ich schlage vor: Blocktitel und die Anzahl der angezeigten Entitäten (Nodes, Benutzer, Terms).
Zuerst ändern wir die Eigenschaft 'page callback' im hook_menu:
function sitemade_menu(){
$items = array();
$items['admin/config/content/content_blocks'] = array(
'title' => 'Benutzer-, Node- und Termblöcke',
'description' => 'Blockverwaltung',
'page callback' => 'drupal_get_form',
'page arguments' => array('_sitemade_content_blocks'),
'access arguments' => array('admin content blocks'),
);
return $items;
}
Beschreibung der Funktion drupal_get_form():
drupal_get_form($form_id)
Wrapper für drupal_build_form(), wenn $form_state nicht benötigt wird.
Parameter von drupal_get_form()
$form_id ist die eindeutige Kennung der Formularfunktion. Existiert diese Funktion, wird der Formular-Array-Konstruktor aufgerufen. Module, die ähnliche $form_id benötigen, können hook_forms() implementieren, um $form_id-Werte auf Konstruktorfunktionen abzubilden.
Weitere übergebene Argumente werden an die Formularfunktion angehängt. Beispiel: Das Formular node_edit benötigt das Node-Objekt, was über hook_form_alter() oder hook_FORM_ID_alter() mit $form_state['build_info']['args'] möglich ist.
Rückgabewert von drupal_get_form()
Das Formular-Array
Nun schreiben wir die Funktion _sitemade_content_blocks() um, damit sie ein Formular-Array zurückgibt.
function _sitemade_content_blocks(){
$form = array(); // Formular-Array initialisieren
$form['nodes-title'] = array(
'#type' => 'textfield',
'#title' => t('Blocktitel für Nodes'),
'#default_value' => variable_get('node_block', ''),
'#size' => 60,
'#maxlength' => 64,
'#description' => t('Blocktitel für Nodes'),
);
$form['node-selected'] = array(
'#type' => 'select',
'#title' => t('Anzahl der Nodes im Block'),
'#options' => array(
1 => t('1'),
2 => t('2'),
3 => t('3'),
4 => t('4'),
5 => t('5'),
6 => t('6'),
7 => t('7'),
8 => t('8'),
9 => t('9'),
10 => t('10'),
),
'#default_value' => variable_get('node_block_range', 5),
'#description' => t('Anzahl der im Block angezeigten Nodes'),
);
$form['users-title'] = array(
'#type' => 'textfield',
'#title' => t('Blocktitel für Benutzer'),
'#default_value' => variable_get('user_block', ''),
'#size' => 60,
'#maxlength' => 64,
'#description' => t('Blocktitel für Benutzer'),
);
$form['user-selected'] = array(
'#type' => 'select',
'#title' => t('Anzahl der Benutzer im Block'),
'#options' => array(
1 => t('1'),
2 => t('2'),
3 => t('3'),
4 => t('4'),
5 => t('5'),
6 => t('6'),
7 => t('7'),
8 => t('8'),
9 => t('9'),
10 => t('10'),
),
'#default_value' => variable_get('user_block_range', 5),
'#description' => t('Anzahl der im Block angezeigten Benutzer'),
);
$form['terms-title'] = array(
'#type' => 'textfield',
'#title' => t('Blocktitel für Terms'),
'#default_value' => variable_get('term_block', ''),
'#size' => 60,
'#maxlength' => 64,
'#description' => t('Blocktitel für Terms'),
);
$form['term-selected'] = array(
'#type' => 'select',
'#title' => t('Anzahl der Terms im Block'),
'#options' => array(
1 => t('1'),
2 => t('2'),
3 => t('3'),
4 => t('4'),
5 => t('5'),
6 => t('6'),
7 => t('7'),
8 => t('8'),
9 => t('9'),
10 => t('10'),
),
'#default_value' => variable_get('term_block_range', 5),
'#description' => t('Anzahl der im Block angezeigten Terms'),
);
$form['actions'] = array('#type' => 'actions'); // Speichern-Button hinzufügen
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Speichern'),
);
return $form;
}
'#type' - Elementtyp.
'#title' - Überschrift.
'#description' - Beschreibung.
'#options' - Dropdown-Optionen.
'#default_value' - Standardwert, hier laden wir gespeicherte Werte.
Das Administrationsformular sollte nun so aussehen:

Wir haben das Formular ausgegeben, jetzt müssen wir die Formularverarbeitung hinzufügen. Dafür verwenden wir die Hooks hook_formID_validate() und hook_formID_submit() für Validierung und Verarbeitung.
Formular-Generierung
Verfügbare Funktionen zur Verarbeitung und Ausgabe von HTML-Formularen in Drupal.
Drupal nutzt diese Funktionen, um die Formularverarbeitung und -anzeige kompatibel zu machen, den Code zu vereinfachen und die Menge an HTML-Code, den Module exakt generieren müssen, zu reduzieren. Die Hauptfunktion dafür ist drupal_get_form(), die den HTML-Code eines Formulars generiert. Ein Formular kann programmgesteuert ohne Benutzerinteraktion mit drupal_form_submit() erstellt werden.
drupal_get_form() akzeptiert, verarbeitet und gibt automatisch den generierten HTML-Code für Module aus. Unten ein Beispiel, wie man drupal_get_form() und andere Funktionen für die Formularerstellung nutzt.
<?php
$form = drupal_get_form('my_module_example_form');
...
function my_module_example_form($form, &$form_state) {
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Absenden'),
);
return $form;
}
function my_module_example_form_validate($form, &$form_state) {
// Validierung der Eingaben.
}
function my_module_example_form_submit($form, &$form_state) {
// Formularverarbeitung.
}
?>
Oder mit zusätzlichen Argumenten:
<?php
$extra = "extra";
$form = drupal_get_form('my_module_example_form', $extra);
...
function my_module_example_form($form, &$form_state, $extra) {
$form['submit'] = array(
'#type' => 'submit',
'#value' => $extra,
);
return $form;
}
?>
Nun schreiben wir die Formularverarbeitung, damit die übermittelten Werte in Drupal-Variablen gespeichert werden. Installieren Sie das Modul Devel, das die Funktion dsm() bereitstellt, welche Arrays und Objekte ausgibt. Dann fügen wir im Modul noch einen Hook hinzu:
function sitemade_content_blocks_submit($form, &$form_values){
dsm($form_values);
}
Damit werden die übermittelten Formularwerte auf dem Bildschirm ausgegeben:

Jetzt können wir die Werte einfach in Variablen speichern:
function sitemade_content_blocks_submit($form, &$form_values){
//dsm($form_values);
variable_set('node_block', $form_values['values']['nodes-title']);
variable_set('user_block', $form_values['values']['users-title']);
variable_set('term_block', $form_values['values']['terms-title']);
variable_set('node_block_range', $form_values['values']['node-selected']);
variable_set('user_block_range', $form_values['values']['user-selected']);
variable_set('term_block_range', $form_values['values']['term-selected']);
}
Das Formular ist fertig. Nach dem Absenden werden die Werte mit variable_set() gespeichert und beim Laden der Formularfelder mit variable_get() als Standardwerte geladen.

Zum Schluss ändern wir noch hook_block_view(), damit Blocktitel und Anzahl der Links in den Blöcken mit variable_get() ausgelesen werden.
function sitemade_block_view($delta = ''){
$block = array(); // leeres Block-Array initialisieren
switch ($delta){
case 1:
$block['subject'] = variable_get('user_block', 'Benutzer'); // Blocktitel ausgeben
$block['content'] = '';
$query = db_select('users', 'u')
->fields('u', array('uid', 'name'))
->orderBy('u.uid', 'DESC')
->range(0, variable_get('user_block_range', 5))
->execute();
$users = $query->fetchAll(PDO::FETCH_ASSOC);
foreach($users as $user){
$block['content'] .= '<div><a href="' . base_path() . 'user/' . $user['uid'] . '">' . $user['name'] . '</a></div>';
}
break;
case 2:
$block['subject'] = variable_get('node_block', 'Nodes');
$block['content'] = '';
$query = db_select('node', 'n')
->fields('n', array('nid', 'title'))
->orderBy('n.nid', 'DESC')
->range(0, variable_get('node_block_range', 5))
->execute();
$nodes = $query->fetchAll(PDO::FETCH_ASSOC);
foreach($nodes as $node){
$block['content'] .= '<div><a href="' . base_path() . 'node/' . $node['nid'] . '">' . $node['title'] . '</a></div>';
}
break;
case 3:
$block['subject'] = variable_get('term_block', 'Terms');
$block['content'] = '';
$query = db_select('taxonomy_term_data', 't')
->fields('t', array('tid', 'name'))
->orderBy('t.tid', 'DESC')
->range(0, variable_get('term_block_range', 10))
->execute();
$terms = $query->fetchAll(PDO::FETCH_ASSOC);
foreach($terms as $term){
$block['content'] .= '<div><a href="' . base_path() . 'taxonomy/term/' . $term['tid'] . '">' . $term['name'] . '</a></div>';
}
break;
}
return $block;
}
Nun kann man das Ergebnis auf der Startseite ansehen. Und nicht vergessen: „Cache leeren nicht vergessen“!
