TEE-08 Frontend Parametrisierung

Aus Contao Community Documentation

MsgError.png Unvollständiger Artikel: dieser Artikel ist noch nicht sauber bearbeitet.

Bitte erweitere ihn und entferne erst anschliessend diesen Hinweis.

Tagebuch einer Extension-Entwicklung

betrifft
TYPOlight Version ab TL 2.8
Extensions Extension Creator


Parameter fürs Modul

Die Ausgabe im Frontendmodul möchte ich gerne in der Modulverwaltung parametrisieren können. Einerseits soll man auswählen können, ob das Modul nur aktive oder nur inaktive, oder alle Paare auflisten soll. Andererseits soll der Sortiermodus zwischen "Nachnamen alphabetisch" und "Nach Altersgruppe aufsteigend" wählbar sein.

Dafür ist der etablierte Weg eine Erweiterung der Tabelle tl_module um die benötigten Felder. Man soll bestehende Fehler wenn möglich recyclen, aber man recycelt dann auch die Beschreibungstexte usw mit, das war für mich nicht passend.

Also habe ich neue Felder angelegt. In der config/database.php meiner Extension:

--
-- Extend table 'tl_module'
--
CREATE TABLE `tl_module` (
  `gw_tp_showonlyactive` char(1) NOT NULL default 'B',
  `gw_tp_couplesorting` char(1) NOT NULL default 'A',
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Hier füge ich also zwei char-Felder hinzu, die Buchstabencodes enthalten (Beim Filter: B = Alle Paare [Both], A = Nur aktive Paare, I = Nur inaktive Paare; Beim Sortieren: A = Alphabetisch, C = Nach Altersklasse [Class]), die ich dann später im Frontend-Ausgabemodul auslesen und interpretieren muss. WICHTIG: Obwohl ich nur eine schon bestehende Tabelle ERWEITERN will, muss ich hier "CREATE TABLE" verwenden. Das Installtool macht das Richtige daraus...

Danach muss ich das Installtool aufrufen, um die neuen Felder anlegen zu lassen.

Dann muss der DCA-Record für tl_module so erweitert werden, dass meine Felder angezeigt werden, wenn in der Dropdown-Liste der zur Verfügung stehenden Module die Turnierpaarliste ausgewählt wird.

Dafür nehmen wir uns system/modules/gw_turnierpaare/dca/tl_module.php vor:

$GLOBALS['TL_DCA']['tl_module']['palettes']['gw_turnierpaarliste'] = '{title_legend},name,headline,type;{sort_legend},gw_tp_showonlyactive,gw_tp_couplesorting;
{protected_legend:hide},protected;{expert_legend:hide},guests,cssID,space';

In der Subpalette für mein Modul füge ich einen neuen Abschnitt mit Überschrift sort_legend ein. Darin werden meine beiden neuen Datenbankfelder angezeigt.

Die müssen noch im DCA definiert werden:

$GLOBALS['TL_DCA']['tl_module']['fields']['gw_tp_showonlyactive'] = array 
( 
    'label'                   => &$GLOBALS['TL_LANG']['tl_module']['gw_tp_showonlyactive'], 
    'default'                 => 'B', 
    'exclude'                 => true, 
    'inputType'               => 'select', 
    'options'                 => array('B','A','I'), 
    'reference'               => &$GLOBALS['TL_LANG']['tl_module']['gw_tp_filteroptions'], 
    'eval'                    => array('mandatory'=>true, 'tl_class' => 'w50') 
); 
$GLOBALS['TL_DCA']['tl_module']['fields']['gw_tp_couplesorting'] = array 
( 
    'label'                   => &$GLOBALS['TL_LANG']['tl_module']['gw_tp_couplesorting'], 
    'default'                 => 'A', 
    'exclude'                 => true, 
    'inputType'               => 'select', 
    'options'                 => array('A','C'), 
    'reference'               => &$GLOBALS['TL_LANG']['tl_module']['gw_tp_sortoptions'], 
    'eval'                    => array('mandatory'=>true) 
);

Der Typ ist select, also eine Dropdown-Box. Die options sind die Werte, die in die Datenbank geschrieben werden sollen. Die reference sind im Gegensatz dazu die Werte, die in der Dropdown-Box angezeigt werden sollen. Hier war mir anfangs unklar, wie genau die Übersetzungen definiert werden müssen. Dazu gleich mehr. Hier setze ich erst mal die Referenz auf ein Array, was in den Sprachfiles definiert wird. Da die Werte in der Modulverwaltung angezeigt werden, habe ich mich dazu entschlossen, sie unter tl_module einzusortieren, aber mit meinem Präfix gw_tp, um Namenskollisionen unwahrscheinlich zu machen.

Nun noch die Definition der Strings in der deutschen Sprachdatei (englisch geht genauso). Da die String zur Modulverwaltung gehören, habe ich mich dazu entschlossen, sie in die Datei system/modules/gw_turnierpaare/languages/de/modules.php zu schreiben. Man hätte auch eine neue Datei tl_module.php anlegen können. Ich weiß nicht, was da "best practice" ist.

Wir ergänzen also die modules.php um:

/** 
 * Back end fields for tl_module 
 */ 
$GLOBALS['TL_LANG']['tl_module']['sort_legend']     = 'Filter und Sortierung'; 
 
$GLOBALS['TL_LANG']['tl_module']['gw_tp_showonlyactive'] = array('Aktive/Inaktive Paare auflisten?', 'Bitte wählen Sie aus, ob nur aktive, inaktive oder alle Paare gelistet werden sollen'); 
$GLOBALS['TL_LANG']['tl_module']['gw_tp_filteroptions'] = array('B' => 'Alle Paare', 'A' => 'Nur aktive Paare', 'I' => 'Nur inaktive Paare'); 
$GLOBALS['TL_LANG']['tl_module']['gw_tp_couplesorting'] = array('Sortiermodus', 'Bitte wählen Sie aus, wie die Liste der Turnierpaare sortiert sein soll'); 
$GLOBALS['TL_LANG']['tl_module']['gw_tp_sortoptions'] = array('A' => 'Alphabetisch', 'C' => 'Nach Altersklasse aufsteigend');

Hier kommt nun der Knackpunkt der reference-Arrays, der mir nicht klar war, und erst durch Abgucken bei anderen Extensions geklärt wurde:

Das reference-Array darf nicht einfach ein aufsteigendes Array der Texte zu den Optionen sein wie das options-Array (also "array('text1','text2','text3');"), sondern es muss ein assoziatives Array mit der Beziehung 'option1' => 'Text1' sein, sonst funktioniert es nicht. Die DCA-Referenz bleibt da leider sehr schwammig.

Auch die Abschnittsüberschrift sort_legend definieren wir hier.

Damit haben wir dieses Ergebnis:

Modul Einstellungen

Leider schaffe ich es in diesem Schritt nicht mehr, die neuen Felder in der Frontendausgabe auch noch auszuwerten (der Kampf mit dem reference-Array hat doch etwas Zeit gekostet). Das muss bis zum nächsten Mal (übernächste Woche) warten, sorry.

Parameter fürs Modul, die Zweite

Nun geht es daran, die Modulparameter aus Schritt 7 im Frontendmodul auch wirklich zu nutzen. Dafür muss ich sie mir zuerst beschaffen. Das geschieht zu Beginn der compile()-Funktion in /system/modules/gw_turnierpaare/gwTurnierpaarliste.php:

        $moduleParams = $this->Database->prepare("SELECT * FROM tl_module WHERE id=?") 
                        ->limit(1) 
                        ->execute($this->id);

$this->id enthält die Modul-ID, und über einen Blick in die Datenbank bekommen wir alle Felder der entsprechenden Zeile und damit auch unsere Parameter.

Die muss ich nun auswerten und entsprechend reagieren. Zunächst das Flag, das mir nur die aktiven Paare, nur die inaktiven oder beide liefert:

 
    $whereClause = ''; 
    if($moduleParams->gw_tp_showonlyactive == 'A') 
    { 
      $whereClause = "WHERE aktiv='1'"; 
    } 
    else 
    { 
      if($moduleParams->gw_tp_showonlyactive == 'I') 
      { 
        $whereClause = "WHERE aktiv=''"; 
      } 
    }

Die Variable $whereClause baue ich später in meinen SELECT der Turnierpaare ein.

Für die Sortierung muss ich die alphabetische Sortierung nach Nachname Herr und Nachname Dame einerseits und die Sortierung nach Startgruppe (und dann Startklasse und erst dann Nachnamen) unterscheiden.

Der erste Fall ist einfach ("ORDER BY partnernachname, partnerinnachname"), der andere aber komplizierter, da die Sortierrreihenfolge nicht alphabetisch ist, sondern sich nach den Altersklassen richten soll, die Jüngsten zuerst. Aber ein wenig googeln hilft, das Problem mit einem SQL-Query zu lösen. Die FIELD()-Funktion liefert mir den Index des Inhalts eines Datenbankfeldes innerhalb einer Liste von Werten. Das kann ich benutzen, um in beliebiger Reihenfolge zu sortieren. Will ich das Feld field in der Reihenfolge "BCA" sortieren, leistet das "ORDER BY FIELD(field,'B','C','A')".

    $orderClause = 'partnernachname, partnerinnachname'; 
    if($moduleParams->gw_tp_couplesorting == 'C') 
    { 
      // Nach Altersgruppen sortieren 
      $fieldstartgruppe="''"; 
       foreach(array('KIN I','KIN II', 'JUN I', 'JUN II', 'JUG', 'HGR', 'HGR II', 'SEN I', 'SEN II', 'SEN III', 'SEN IV') as $gruppe) 
      { 
        $fieldstartgruppe .= ",'".$gruppe."'"; 
      } 
      $fieldstartklasse="''"; 
      foreach(array('-', 'E','D', 'C', 'B', 'A', 'S', 'PRO', 'LL', 'OL', 'RL', '2. BL', '1. BL') as $klasse) 
      { 
        $fieldstartklasse .= ",'".$klasse."'"; 
      } 
 
      $orderClause = "FIELD(startgruppe,".$fieldstartgruppe."), FIELD(startklassestandard,".$fieldstartklasse."), FIELD(startklasselatein,".$fieldstartklasse."), partnernachname, partnerinnachname"; 
    }

Defaultmäßig wird alphabetisch nach den Nachnamen sortiert. Wenn aber das gw_tp_couplesorting-Feld 'C' ist, dann wird aus den möglichen Werten der Altersgruppe und der Startklasse jeweils ein String zusammengebaut, der dann in $orderClause zum "ORDER BY"-Teil zusammengebaut wird.

So wird zuerst nach der Altersgruppe (in vorgegebener Reihenfolge), dann nach den Startklassen Standard und Latein (in vorgegebener Reihenfolge) und schließlich nach den Nachnamen sortiert. Natürlich hätte ich die Liste der Gruppen und Klassen direkt als String definieren können, statt ein Array anzulegen, mit einer Variable drüber zu laufen, um daraus wieder einen String zu machen.

Aber der Gedanke war, das options-Feld der DCA-Definition der entsprechenden Felder im DCA-Record zu nutzen. Eine Änderung der möglichen Optionen dort würde dann auch gleich an dieser Stelle genutzt werden. Leider scheint die DCA-Definition des Backend-Moduls an dieser Stelle (Frontend-Modul!) leider nicht geladen zu sein, $GLOBALS['TL_DCA'] ist zumindest nicht vorhanden. Schade! Aber vielleicht lagere ich die Arrays noch in eine gemeinsame, geteilte Include-Datei aus, die ich in DCA-Definition und im Frontendmodul nutzen kann.

Darum bleibt es erstmal bei der Schleife über den Arrayelementen.

Schließlich muss das ursprüngliche SELECT-Statement noch um die neuen Variablen $whereClause und $orderClause erweitert werden:

    $objPaare = $this->Database->execute("SELECT * FROM tl_gw_turnierpaare " . $whereClause . "ORDER BY " . $orderClause);

Ich definiere nun zwei Module, einmal die Liste der aktiven Turnierpaare, die eben nur die aktiven Paare anzeigt, sortiert nach Startgruppen und Klassen, und eine Liste der inaktiven Paare, alphabetisch sortiert. Beide Module füge ich in in eine Seite als Inhaltselemente ein.

Das Ergebnis:

Frontend Ausgabe

Oben das Modul, das die aktiven Turnierpaare sortiert nach Altersgruppe anzeigt, unten das Modul, das die inaktiven Paare alphabetisch sortiert anzeigt. Die graue Farbe bei den Inaktiven wird auch noch geändert, und im nächsten Schritt wird es an den "Detail"-Link gehen.

Ansichten
Meine Werkzeuge

Contao Community Documentation

<Kellner> und einmal Filet?
<backbone87> Nein Olli, nicht Philip!

Navigation
Verstehen
Verwenden
Entwickeln
Verschiedenes
Werkzeuge