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“!