Archiv der Kategorie: Formular

Drupal Bewertungsformular mit AJAX

Was in WordPress so schön funktioniert hat, sollte doch auch in Drupal zu machen sein: ein Bewertungsformular, das sich beim Abschicken einer neuen Bewertung selbst updated, eine genaue Beschreibung dazu findet man in diesem Artikel im Blog zum schwarzen Pinguin. Man kann Noten von sehr gut bis ungenügend vergeben, und es gibt einen Button zum Abschicken der Bewertung. Dazu werden die evtl. bereits vorhandenen Bewertungen und die Durchschnittsnote angezeigt, aussehen tut das Ganze so:

bewertungformular1
bewertungformular1

Voraussetzungen in Drupal

Ich werde dieses Formular nur für einen ausgesuchten Inhaltstypen anlegen, ich nehm mal die Artikel. Dazu brauchen wir einen Template Override – das hört sich schlimmer an als es ist.

Um die Bildschirmanzeige für alle Inhalte vom Typ Artikel zu ändern, klemmt man sich aus dem Verzeichnis ../themes/[dein theme]/templates die node.tpl.php und macht eine Kopie davon. Diese benennt man um in node–article.tpl.php (doppelter Bindestrich!). Dann sucht man sich die richtige Stelle nach dem Content aus, das ist in meinem Fall nach dem Block:

<div class="content clearfix"<?php print $content_attributes; ?>>
<?php
// We hide the comments and links now so that we can render them later.
hide($content['comments']);
hide($content['links']);
print render($content);
?>
</div>

Da ich das Formular nur in der Einzelansicht anzeigen möchte, füge ich hier eine if-Abfrage ein, die sieht erstmal so aus:

<?php
if ($view_mode == 'full'){

echo "<h1>Hier kommt das Formular hin</h1>";
}
?>

Cache leeren nicht vergessen, und nachgucken ob der Text an der richtigen Stelle angezeigt wird. Dann kann man hier den Funktionsaufruf reinpacken:

if ($view_mode == 'full'){

el_bew_ajax();

}

Ein eigenes Modul für das Formular

Das Formular selber packe ich in ein selbstgebautes Modul, zur Erstellung eines einfachen Moduls in Drupal kann man in diesem Artikel nachschlagen. Zuerst kommt mal das HTML für die Anzeige des Formulars rein, das wird in eine Funktion gesteckt:

function el_bew_ajax(){

echo '<div style="border:1px dotted #000; text-align:center; padding:10px;">';
echo '<h4>Dir gefällt dieser Beitrag?</h4>';
echo '<p>Dann bewerte ihn!</p>';
echo '</div>';

echo " <form action = '' method='post'>";

echo "<fieldset>
<div id = 'noten' class = 'noten' style = 'border:2px solid blue; padding :4px;'>
<input type='radio' name='note' value='1'>sehr gut
<input type='radio' name='note' value='2'>gut
<input type='radio' name='note' value='3'>befriedigend<br>
<input type='radio' name='note' value='4'>ausreichend
<input type='radio' name='note' value='5'>mangelhaft
<input type='radio' name='note' value='6'>ungenügend

<input type ='button' name = 'absenden' class = 'bew-button' value = 'abschicken' onclick='el_bew_ajax()'/>
</div>
</fieldset>";
echo "</form>";


}//ende function el_bew_ajax

Das habe ich 1:1 aus der oben zitierten WordPress-Lösung kopiert, funktioniert hier genauso. Das Javascript wird bei Klick auf den ‚absenden‘-Button aufgerufen, dazu gleich mehr.

Eine Tabelle für die Bewertungen

Auch diese sieht genau wie in der WordPress-Lösung aus und enthält drei Felder, eine Autowert-ID, ein Int für die nid und ein Int für die Note:

drupal_bewertungen
drupal_bewertungen

Die Logik für die Anzeige der bereits vorhandenen Bewertungen

Diese musste ich nur ein wenig auf Drupal-Verhältnisse anpassen, die Datenbankabfrage funktioniert hier mit db_query. Die aktuelle Beitragsid ist ein bisschen sperrig abzufragen, da suche ich noch eine hübschere Lösung:

//nid des aktuellen Beitrags bestimmen und in span schreiben
$nid = 0;
if (arg(0) == 'node' && is_numeric(arg(1))) {
$nid = arg(1);
}
echo 'NID dieses Beitrags: <span id = "beitragsid">'.$nid.'</span>';

//******aktuelle Benotungen abholen und Durchschnitt berechnen


$result = db_query('SELECT * FROM {bewertungen} WHERE nid = '.$nid.'');
$gefunden = $result->rowCount();


$durchschnitt = 0;
foreach ($result as $record) {
$durchschnitt = $durchschnitt + $record->note;

}
if ($gefunden != 0){ 
$durchschnitt = $durchschnitt / $gefunden;
}
echo "<span id = 'ausgabe'>".$gefunden." Bewertungen gefunden, Durchschnitt: ".$durchschnitt."<span>";

Das Javascript

…wird  am Anfang der .module-Datei eingebunden, und zwar so:

function ajax_el_init() { 

drupal_add_js(drupal_get_path('module', 'ajax_el') . '/test_ajax_el.js');

}

Die js-Datei liegt bei mir einfach im selben Verzeichnis wie das Modul. Sie sieht wird in einen Wrapper eingebunden, damit man $ für jQuery verwenden kann:

(function ($) {
function el_bew_ajax(){

//Hier kommt der Code

}//end function el_bew_ajax
})(jQuery);

Die ganze Funktion für den Ajax-Call sieht folgendermassen aus:

(function ($) {
function el_bew_ajax(){


//Beitragsid aus span holen
var akt_id = document.getElementById("beitragsid").innerHTML;

//Note aus den Radiobuttons holen
var akt_note = $("input:radio[name=note]:checked").val();

//Debug-Ausgabe
//alert(akt_note + ' ' + akt_id);

//Check ob keine Note angewählt, Abbruch
if (typeof akt_note === 'undefined'){
alert('Bitte eine Note wählen!');
return;}

//***********************ajax-call
if (window.XMLHttpRequest)
{
// AJAX nutzen mit IE7+, Chrome, Firefox, Safari, Opera
xmlhttp=new XMLHttpRequest();
}
else
{
// AJAX mit IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("ausgabe").innerHTML = xmlhttp.responseText;

}
}
xmlhttp.open("GET","../sites/all/modules/ajax_el/callback_ajax_el.php?id="+akt_id+"&note="+akt_note,true);

xmlhttp.send();



//**********************end ajax call
}//end function el_bew_ajax
})(jQuery);

Ich hole mir am Anfang die nid des Beitrags und die aktuelle Note aus dem Formular und gebe eine Meldung aus falls keine Benotung angewählt wurde.

Die Funktionalität für den Ajax-Call ist die selbe wie die, die wir schon für den Ajax-Autocomplete in diesem Beitrag verwendet haben, das drösel ich hier jetzt nicht nochmal auf.  Der einzige Unterschied ist, dass hier am Ende zwei Parameter statt nur einem an die Callbackfunktion übergeben werden.

Die Callback-Funktion

ist auch recht einfach. Ich hole mir die zwei Werte für die Note und die nid des Beitrags, mache einen Insert auf die Tabelle bewertungen und berechne den neuen Durchschnitt sowie die Anzahl der Bewertungen. Zurückgegeben werden die neuen Werte, die kriegt unser Script als  response und schreibt sie in die div ‚ausgabe‘ im Formular.

$nid = '';
if ( isset($_GET['id']) )
{
$nid = $_GET['id'];
}
$note = '';
if ( isset($_GET['note']) )
{
$note = $_GET['note'];
}

$pdo = new PDO('mysql:host=localhost;dbname=druneu', '******', '*******');

//neue Note erstmal einfügen
$sql = "INSERT INTO bewertungen (nid, note) VALUES (".$nid.",".$note.")";
$neu = $pdo->query($sql);

//Suche nach aktueller nid
$sql = "SELECT * FROM bewertungen where nid = ".$nid."";
$records = $pdo->query($sql);
$gefunden = $records->rowcount();

$durchschnitt = 0;
foreach ($records as $row) {

$durchschnitt = $durchschnitt + $row['note'];
}
if ($gefunden != 0){ 
$durchschnitt = $durchschnitt / $gefunden;
}
echo $gefunden." Bewertungen vorhanden, Durchschnittsnote = ".$durchschnitt;

Das war schon der ganze Zauber! Man kann jetzt noch die Durchschnittsnoten runden und per switch case die entsprechenden Bezeichnungen vergeben (1=sehr gut… 6=ungenügend), aber das ist Feintuning, das spare ich mir jetzt.

Aussehen tut das Ganze jetzt so:

bewertungsformular2
bewertungsformular2

Tipp: damit man sich beim Testen nicht schwarz ärgert wenn was nicht gleich funktioniert: Cache leeren nach jeder Script-Änderung!

Rezeptsuche mit AJAX Autocomplete 2: das Javascript und die PHP-Datei

Das Javascript

Wir haben ja im vorigen Beitrag unsere Javascriptdatei rezepte_suche.js geladen, jetzt stelle ich sie hier mal in aller Kürze vor. Die ist nicht auf meinem Mist gewachsen, das ist eine Standardprozedur für einen AJAX-Call die ich mir zusammengegooglet und nach meinen Bedürfnissen angepaßt habe. Sie enthält genau eine Funktion, nämlich die rezepte_suche mit dem Parameter inhalt, in dem steckt der vom Benutzer eingegebene Inhalt des Textfeldes aus dem Formular:

function rezepte_suche(inhalt)
{
 if (inhalt=="")
 {
  return;
 }
 if (window.XMLHttpRequest)
 {
  // AJAX nutzen mit IE7+, Chrome, Firefox, Safari, Opera
  xmlhttp=new XMLHttpRequest();
 }
 else
 {
  // AJAX mit IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
 }
 xmlhttp.onreadystatechange=function()
 {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
  {
   
   document.getElementById("liste").innerHTML=xmlhttp.responseText;
  }
 }
 xmlhttp.open("GET","http://localhost/drumenus/sites/all/modules/autocom/rezeptesuche.php?q="+inhalt,true);

 xmlhttp.send();
}

Was passiert hier? Zuerst wird abgefragt, ob inhalt leer ist und in dem Fall nur ein return ausgelöst.

Wenn inhalt nicht leer ist, greifen zwei IF-Abfragen, die Browserabhängig die Variable xmlhttp unterschiedlich belegen. Wir schauen mal nur den ersten Zweig an:

xmlhttp=new XMLHttpRequest();

Hier wird ein neues Objekt vom Typ XMLHttpRequest angelegt, das wird im Folgenden weiterverarbeitet. Wer dazu Genaueres wissen möchte dem sei diese Seite der wikibooks empfohlen.

Wenn sich am Status des Formularfeldes etwas ändert, feuert folgende Funktion:

xmlhttp.onreadystatechange=function()
 {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
  {
   
   document.getElementById("liste").innerHTML=xmlhttp.responseText;
  }
 }

Die div mit der id liste kriegt einen neuen Inhalt, nämlich den Rückgabewert des Requests. Wir der aussieht, wird in unserer PHP-Datei geregelt, dazu gleich mehr.

Wichtig ist jetzt noch der open-Aufruf:

xmlhttp.open("GET","http://localhost/drumenus/sites/all/modules/autocom/rezeptesuche.php?q="+inhalt,true);

Ich hab hier den Pfad zur PHP-Datei noch fest verdrahtet, das läßt sich sicher auch eleganter lösen, aber für Testzwecke tuts das. Die PHP-Datei kriegt als Parameter unseren inhalt mit, das ist immer noch der Inhalt des Formularfeldes so wie ihn der Benutzer eingegeben hat. Fehlt nur noch der Auslöser:

xmlhttp.send();

Und Schuß! Das setzt den Request ab.

Die aufgrufene PHP-Datei

Die benimmt sich nicht anders, als wenn sie von einem Formular aus aufgerufen würde, und sie übernimmt den Parameter inhalt in der Variablen q. Ansonsten ist sie recht übersichtlich:

<?php

$rezept = '';
if ( isset($_GET['q']) )
{
  $rezept = $_GET['q'];
}

$pdo = new PDO('mysql:host=localhost;dbname=drumenus', '*****', '*****');

//Suche nach enthaltenem String %suchstring%
$sql = "SELECT * FROM node where title like '%".$rezept."%' and type like 'rezept' order by title";
$records = $pdo->query($sql);

foreach ($records as $row) {
        
        echo "<option>".$row['title']." #".$row['nid']."</option><br>";
        
    }
?>

Ich hole mir erstmal den Inhalt von q auf die Variable $rezept. Dann verbinde ich mich mit der Drupal-Datenbank und hole mir aus der node-Tabelle mit dem Select alle Datensätze der Rezepte (type like ‚rezept‘), die den Inhalt von $rezept im Titel enthalten. Innerhalb der Foreach-Schleife wirds dann nochmal interessant, ich klemme vor und nach dem Titel des Rezeptes die <option>-Tags dran, die brauchen wir nachher im Formular für die Datalist. Ausserdem nehme ich noch die nid mit, die brauchen wir dann für die Ausgabe des Rezeptes. Das wars dann aber auch schon.

Das Formular ist jetzt scharfgeschaltet

Wenn der Benutzer jetzt zum Beispiel salat in das Textfeld eingibt, erhält er eine Liste aller Rezepttitel, in denen der String salat vorkommt:

salat
salat

Jetzt muss nur noch etwas passieren, wenn er einen der Einträge auswählt und auf Return drückt. Ich hab das so gelöst: in der autocom.module kommt nach dem Formular noch folgender Code:

if (isset($_POST['ausgesucht'])){
    
    echo "Vielen Dank! Ihre Auswahl: <h2>".$_POST['ausgesucht']."</h2><br>";

    $text = strstr($_POST['ausgesucht'], '#');
    $text=substr($text,1); 
    
    $options = array('absolute' => TRUE);
    $nid = $text; // Node ID
    $url = url('node/' . $nid, $options);
    
    echo "<h2><a href = ".$url.">Link zum Rezept</a></h2>";

    } //ende von if isset

Wenn der Benutzer einen Eintrag ausgewählt hat (If (isset…)), zerlege ich mir die Auswahl und hole mir nur die nid nach dem #. Zu der wiederum hole ich mir die URL des betreffenden Nodes, und gebe damit einen Link zum Rezept aus. Das wars! Aussehen tut das Ganze so:

link_zum_rezept
link_zum_rezept

Ich hab hier jetzt mal mit dem Link gearbeitet, man könnte hier natürlich auch mit der nid in die Tabelle field_data_body gehen und sich den body_value ausgeben lassen, das wäre der komplette Text des ausgewählten Rezeptes, aber das ist reine Geschmackssache.

Drupal-Puristen werden mich jetzt wahrscheinlich steinigen, weil man „das so nicht machen kann“, aber der Autocomplete funktioniert jedenfalls ohne allzu grossen Aufwand. Es gibt sicher hier und da noch ein paar Optimierungspotentiale, was man unbedingt noch angehen sollte wäre der fest verdrahtete Pfad zu der PHP-Datei in der rezepte_suche.js, das ist sicher nicht so besonders gut gelöst, aber für Demozwecke tuts das, finde ich. mir hats Spaß gemacht, und das Ergebnis ist ganz ansehnlich.

Rezeptsuche in Drupal mit AJAX Autocomplete

Einleitung

Wahrscheinlich werden da jetzt alle Drupal-Puristen Zetermordio schreien, dass man das so nicht machen kann, aber wenns funktioniert… ich bin da nicht so pingelig.

Das Vorhaben: Suche mit Autocomplete

Ich hab ja über 300 Rezepte in meinem Drupal-Kochbuch, und was in WordPress funktioniert hat, sollte auch in Drupal machbar sein: eine Suche mit Autocomplete bzw. auf Deutsch Auto-Vervollständigung. Das heisst, wenn der Benutzer in das Suchfeld einige Buchstaben eingibt, sollen per AJAX gematchte Einträge als Vorschläge in der Liste auftauchen. Dabei verwende ich die HTML5-Datalist, auch wenn die browserabhängig unterschiedliche Ergebnisse liefert, darüber habe ich mich im letzten Beitrag näher ausgelassen. Macht mir aber jetzt nicht wirklich viel aus, man muss es halt nur wissen.

Wir bauen uns ein Modul

Wir packen die ganze Sache natürlich in ein Modul, und das kriegt einen eigenen Menüeintrag, so gehts am Einfachsten. Zur Modulerstellung in Drupal sag ich jetzt nicht mehr viel, das hatten wir schon ausführlich in diesem Artikel und anderswo.

Das Modul heisst bei mir autocom, dazu brauchts erstmal die autocom.info, die sieht bei mir so aus:

name = Autocom
description = Dieses Modul soll Autocompleten
core = 7.x
package = "MyFunctions"
version = "7.1-1.1"

Und dann brauchen wir natürlich noch die autocom.module, zu der ist etwas mehr zu sagen, in der laden wir uns nämlich erstmal die für AJAX benötigte Javascript-Datei. Das passiert ganz oben im File:

function autocom_init() {  
     
     drupal_add_js(drupal_get_path('module', 'autocom') . '/rezepte_suche.js');
    
    }

Mit der Syntax [modulname]_init wird Drupal angewiesen, diese Anweisung beim Laden des Moduls auszuführen. drupal_add_js() ist für das Laden von Javascript zuständig, das drupal_get_path( ‚module‘, ‚[modulname]‘) holt uns den Pfad zum angegebenen Modul, und an den hängen wir unsere js-Datei mit dran, weil die mit im Modulverzeichnis liegt. Was die Scriptdatei macht, dazu später mehr.

Die Funktion für das Suchformular kommt als nächstes in die autocom.module, die sieht erstmal so aus:

function evi_auto(){
      
echo "<h1>Beispiel Rezeptsuche mit AJAX</h1>";
echo "<form action='#' method='post'>";
echo "<input type='text' size='80' name = 'ausgesucht' value='' autocomplete='off' onkeyup='rezepte_suche(this.value)' list = 'suchliste'>";

echo "<datalist id='suchliste'>";

 echo "<div id =liste>";
 echo "</div>";

 echo "</datalist>";

echo "</form>";
}

Egentlich ein ganz normales Formular mit einem Eingabefeld vom Typ Text. Aber hier passieren noch drei eminent wichtige Dinge:

  1. onkeyup = ruft die js-Funktion rezepte_suche() auf, die steckt in der rezepte_suche.js, die wir vorher geladen haben. Die Funktion kriegt als Parameter this.value mit, also den aktuellen Wert des Textfeldes. Onkeyup feuert, wenn der Benutzer eine Taste gedrückt und wieder losgelassen hat.
  2. Der Parameter list = ‚suchliste‚ des Textfeldes definiert, aus welchem HTML-Element die Datenliste für das Dropdownfeld genommen werden soll, nämlich aus der Datalist mit der id = „suchliste“
  3. Innerhalb der Datalist steckt eine Div mit der id= ‚liste‘, in die schreibt nachher unser AJAX-Call sein Ergebnis, dazu gleich mehr.
  4. Wichtige Ergänzung: das Texteingabefeld sollte unbedingt den Parameter autocomplete = ‚off‘ mitkriegen,  sonst pfuscht der Browser mit Einträgen hinein, die er aus anderen Formularen gecached hat.

Wenn man das Modul angelegt und aktiviert hat, sollte das Formular jetzt etwa so aussehen:

formular_leer
formular_leer

Es passiert natürlich noch nichts wenn man da etwas eingibt, da uns die js-Funktion und die zugehörige PHP-Datei noch fehlen, aber dazu gibts einen neuen Beitrag.

 

Erster Anlauf für das Bewertungsformular mit Template Override

Ich habe ja noch keinen vernünftigen Ansatz dafür gefunden, wie man ein Webform-Formular in ein Template einbindet, und bin ganz stark in Versuchung, den „kleinen Dienstweg“ zu nehmen und mein Formulärchen einfach per selbstgebauter PHP-Funktion einzubinden, so wie ich das in Joomla schon gemacht habe, näheres dazu in diesem Artikel.

Ich brauche Titel und/oder ID

Der Knackpunkt bei der Sache ist, beim Abschicken des Formulars brauche ich den Titel oder wenigstens die ID des Rezeptes, von dem aus das Formular verschickt wurde, sonst taugt das alles nix.

Ich probiers mal mit einem Template-Override

Der geht nämlich in Drupal gar nicht schwer. Um einen Override für den Inhaltstyp Blogeintrag anzulegen, geht man im Verzeichnis themes->[dein_theme]->templates hin und legt sich eine Kopie der Datei node.tpl.php an. Diese benennt man um in node–blog.tpl.php (doppelter Strich!), und jetzt kann man werken. Ich hab mal ein kleines Formular reingesetzt, und zwar nach nach der Div für den Content, also nach dem Block:

<div class="content clearfix"<?php print $content_attributes; ?>>
    <?php
      // We hide the comments and links now so that we can render them later.
      hide($content['comments']);
      hide($content['links']);
      print render($content);
    ?>

Hier sitzt jetzt mein kleines Formulärchen, das sieht so aus:

  <h2>Ihre Meinung ist mir wichtig – bitte bewerten Sie dieses Rezept!</h2>
 <form action='#' method='post'>
    <br>
    <input type='radio' name='Bewertung' value='War nix'>War nix<br>
    <input type='radio' name='Bewertung' value='War prima'>War prima<br>
    <input type='submit' name='absenden' value='Bewertung absenden'>
</form>

Damit hätten wir es schon mal an der richtigen Stelle platziert, zumindest wenn man das ganze Rezept anschaut:

bewertungsformular
bewertungsformular

Was mir weniger gefällt ist, dass das Formular so auch in der Blog-Ansicht nach dem Teaser auftaucht:

blog_mit_form
blog_mit_form

Aber darum kümmere ich mich später, jetzt holen wir uns erstmal den Titel des Rezeptes, der steckt nämlich praktischerweise in einer der verfügbaren Variablen – nachzulesen im Header der Template-Datei, ganz oben, da isser: $title.

Da haben wir doch schon alles: Mail kann verschickt werden

Und zwar mit dem selben simplen PHP-Scripterl, das ich schon in Joomla verwendet habe:

 <?php

        if (isset($_POST['absenden'])){
        if (isset($_POST['Bewertung'])){
            $note = $_POST['Bewertung'];
            echo 'Vielen Dank für Ihre Bewertung: '.$note;

             //hier kommt die Mechanik fürs Wegschreiben hin
             // Die Nachricht
                $nachricht = $title." ".$note;
                $nachricht = wordwrap($nachricht, 70);

                // Send
                mail('evi.s.leu@gmx.de', 'Rezeptbewertung', $nachricht);

        }
        else{
        echo 'Bitte eine Bewertung auswählen!';
        }
}
?>

Damit landet in meinem Mail-Output zum Beispiel:

To: evi.s.leu@gmx.de
Subject: Rezeptbewertung
X-PHP-Originating-Script: 0:node--blog.tpl.php

Bärli-Spezial - viele-Kräuter-Sauce War prima

Das erfüllt seinen Zweck, mehr brauch ich eigentlich gar nicht. Aber: es funktioniert nur in der ganzen Ansicht eines Rezeptes richtig!

Jetzt muss das Formular dringend aus der Blogansicht raus

Und zwar wirklich ganz dringend, weil es sonst nämlich E-Mails für alle 10 auf der Seite sichtbaren Rezepte verschickt! Ich glaube, ich hab da auch schon eine Lösung, aber dafür gönn ich mir eine kleine Pause und einen frischen Kaffee.

Na bitte geht doch: mit $view_mode

Ich hab mir die verfügbaren Variablen im Template nochmal genau angeguckt, und bin da auf die sehr praktische Sache mit dem view_mode gestossen:

$view_mode: View mode; for example, "full", "teaser".

Dann hab ich mein Formular samt Auswertungslogik in eine Funktion gepackt, die in meine Bibliothek evismodule.module reingestellt und rufe im Template jetzt nur noch die Funktion mit dem Parameter $title auf, und zwar nur im Full mode:

if ($view_mode == 'full'){
    bewertungsformular($title);
  }

Das war schon der ganze Zauber! Jetzt ist das Formular aus der Blogansicht draussen, in der ganzseitigen Ansicht drin, und verschickt brav nur eine einzelne E-Mail. Perfetto! Das hatte ich mir schwieriger vorgestellt.

Und was ist mit der Datenbank?

Ja klar wollen wir die abgeschickten Formulare auch in einer Tabelle speichern, das gelingt mit folgendem Code, der kommt direkt nach der mail-Anweisung rein:

$nid = db_insert('rezeptbewertungen')
                  ->fields(array(
                    'titel' => $titel,
                    'note' => $note,
                    'datum' => $datum,
                  ))
                  ->execute();

Das hab ich direkt aus der Drupal-Doku zum Thema Insert Queries übernommen. Sehr straightforward, gefällt mir sehr gut. Das setzt natürlich voraus, dass eine Tabelle namens rezeptbewertungen auch existiert und mindestens die drei Felder titel, note und datum hat, aber das sollte ja hinzukriegen sein.

Damit funktioniert unser Bewertungsformular so wie es soll, und ich mach hier einen Break.

 

Drupal Formulare mit Webforms

Der angesagte Formulardesigner für Drupal ist wohl Webforms, und ich fand den angenehm unkompliziert, das machen wir jetzt im Schnelldurchgang. Webform benötigt die ctools und Views, aber ohne die beiden ist ohnehin keine Drupal-Seite komplett, die sollten zur Standardausstattung gehören.

Nach der Installation findet sich unter Inhalt hinzufügen der neue Inhaltstyp Webform. Man hat hier zunächst mal die Option, einen neuen Menüeintrag für das Formular  anzulegen. Dann landet man im Fenster Form Components, hier sollte man zuerst mal unter E-Mails eine eigene E-Mail-Adresse angeben, sonst werden keine Mails verschickt.

email_hinzufuegen
email_hinzufuegen

Dann kann man unter Form Components ganz unkompliziert Formularfelder hinzufügen, ich lass es mal ganz schlicht beim Namen und der Nachricht:

zwei_form_felder
zwei_form_felder

Wenn man nichts weiter macht, kommt diese kleine Formular dabei heraus:

nachricht_an_evi
nachricht_an_evi

Man kann jetzt noch unter Form Settings/Confirmatioen Message einen deutschen Text zur Bestätigung eingeben. Was ich nicht gefunden habe: wie man den Linktext „Go back to form“ eindeutscht… Man kann zwar unter Form Settings ->Redirection Location No redirect anwählen, dann wird nach dem Versand die Formularseite neu geladen, aber dafür bekommt man dann eine Drupal-Meldung, die ist auch nicht schöner:

versandt
versandt

Aber das führt mir jetzt ein bisschen zu weit, ich schau ein andermal, ob sich dafür eine schönere Lösung findet.

Formulare in Blocks

Wenn man das Formular in einem Block nutzen will, muss man unter Form Settings->erweiterte Einstellungen „Available as Block“ anhaken, dann taucht das Formular in der Liste der vefügbaren Blocks auf. Ich wüsste jetzt zwar nicht wo ich das nutzen sollte, es sei aber der Vollständigkeit halber erwähnt.

Formulare in Inhalten

Man kann jetzt auch bei den Inhaltstypen unter dem neuen Punkt „Webform“ die Option „Enable webform Functionality“ für den aktuellen Inhaltstyp anwählen, dann kann man beim neu Anlegen eines Inhalts auch gleich ein neues Formular mit anlegen.

Es wird auch mitprotokolliert

Die abgeschickten Formulare werden übrigens in der Datenbank gespeichert, man werfe mal einen Blick auf die Tabelle webform_submitted_data.

Was ich noch nicht gefunden habe: ein Formular automatisch am Ende jedes Beitrags

Wofür ich das brauche? Für mein Bewertungsformular! Ich möchte doch gern am Ende jedes Rezeptes mein kleines Bewertungsformular haben, damit mir mein geneigtes Publikum die Meinung zum Rezept mitteilen kann. Dafür werde ich wahrscheinlich einen Layout-Override brauchen, und dafür gibts einen neuen Beitrag.

 

 

 

Weiter gehts mit den Inhalten

Die neuesten Rezepte

Jetzt fehlt auf jeden Fall noch die Anzeige der letzten eingestellten Rezepte, dafür gibt es einen Block „Neueste Blogbeiträge“, den schubse ich mal in die zweite Sidebar. Ich hab ihn umbenannt in „Die neuesten Rezepte“ und auf 10 anzuzeigende Einträge gestellt. Es sind erst fünf Rezepte im Blog, das stimmt schon so.

neueste_rezepte
neueste_rezepte

Was machen wir als Nächstes?

Das Kontaktformular

Das klappt in Drupal ohne weiteres mit Bordmitteln. Unter Module Contact aktivieren, dann kann man unter Struktur->Kontaktformular die Grundeinstellungen konfigurieren. Dann unter Menüs->Link hinzufügen einen neuen Menüpunkt z.B. namens Kontakt anlegen und als Pfad contact eingeben, das wars schon. Das sieht dann so aus:

kontaktformular
kontaktformular

Das tuts auch für meine Zwecke erstmal völlig, jedenfalls vorläufig. Über Formulareditoren für Drupal wird es einen eigenen Beitrag geben, da muss ich noch etwas recherchieren. Jetzt gibts erst mal:

Das Zufallsrezept

Auch das habe ich mit Views hingepfriemelt, mal sehen ob ich es nachvollziehen kann:

Struktur->Views->Add new View, Namen und Pfad vergeben, Anzeigen Inhalt of type Blogeintrag.

Create a page, Items to display 1, Continue&Edit.

Sort Criteria Inhalt entfernen. Sort Criteria hinzufügen Global Random, Speichern

Mit Struktur->Menüs->Link hinzufügen die eben erstellte Seite mit dem Pfad hinzufügen.

Das müsste es eigentlich gewesen sein! Jetzt fehlt nur noch eine Funktionalität „Zufallsrezept neu laden“, da muss ich mal gucken ob ich das noch hinkriege. Man kann ja auch einfach F5 drücken…

Zwischenbemerkung: ich brech dann doch mal eine Lanze für Views

Auch wenn ich noch im Stadium des Herumprobierens bin und die meisten Sachen nur mit viel Trial&Error hinkriege: Views ist ein mächtiges Werkzeug, damit macht Drupal gleich doppelt so viel Spaß! Es braucht eben doch eine längere Einarbeitung, aber für einen alten Datenbanker ist es dann doch nicht gar so schwer zu erraten, was sich hinter vielen der Optionen versteckt, ein Order by oder Group by oder was auch immer, da kommt man schon drauf wenn man sich etwas damit beschäftigt.  Dolles Ding!