TEE-07 Frontend Simpel-Version

Aus Contao Community Documentation

Version vom 5. Februar 2011, 19:16 Uhr von Stefan.sl (Diskussion | Beiträge)

(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
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


Endlich Frontend!

Nach soviel Kampf hinter den Kulissen wird jetzt endlich was im Frontend angezeigt und - um das vorweg zu nehmen - das klappt ziemlich reibungslos.

Zunächst mache ich eine "Simpel-Version" des Frontends, die erst mal was anzeigt. Verfeinerungsschritte kommen dann nach und nach dazu. Erstmal muss das schnelle Erfolgserlebnis her.

Zunächst mal müssen die Frontendmodule in system/modules/gw_turnierpaare/config/config.php "registriert" werden:

// Front end module 
array_insert($GLOBALS['FE_MOD']['turnierpaare'], 0, array 
( 
    'gw_turnierpaarliste'	=> 'gwTurnierpaarliste', 
    'gw_meldeliste'			=> 'gwMeldeliste' 
));

turnierpaare scheint die Zwischenüberschrift zu sein, die man in der Dropdown-Liste der zur Verfügung stehenden Module zu sehen kriegt. Die Keys in dem Array sind einfach nur die Bezeichner, die durch die Sprachdateien auch übersetzt werden. Die Values dahinter sind die Namen der Frontendklassen. Zu jeder Frontendklasse existiert /system/modules/gw_turnierpaare/*.php mit der entsprechenden Klassendefinition.

Damit in der Modul-Dropdown-Liste nicht das hässliche turnierpaare steht, muss die Sprachdatei erweitert werden, z.b. system/modules/gw_turnierpaare/languages/de/modules.php um:

$GLOBALS['TL_LANG']['FMD']['turnierpaare'] = array('Turnierpaare');

Nun kommt das eine große Puzzle-Teil für die Frontendausgabe: Die PHP-Klasse, die unsere Inhalte aus der Datenbank holt, aufbereitet und an das Template weiterreicht:

class gwTurnierpaarliste extends Module 
{ 
    /** 
     * Template 
     * @var string 
     */ 
    protected $strTemplate = 'gw_turnierpaarliste'; 
    /** 
     * Generate module 
     */ 
    protected function compile() 
    { 
    $arrPaare = array(); 
    $objPaare = $this->Database->execute("SELECT * FROM tl_gw_turnierpaare ORDER BY partnernachname, partnerinnachname"); 
    while ($objPaare->next()) 
    { 
      $newArr = array 
      ( 
        'partnernachname' => trim($objPaare->partnernachname), 
        'partnervorname' => trim($objPaare->partnervorname), 
        'partnerinnachname' => trim($objPaare->partnerinnachname), 
        'partnerinvorname' => trim($objPaare->partnerinvorname), 
        'startgruppe' => $objPaare->startgruppe, 
        'startklasselatein' => $objPaare->startklasselatein, 
        'startklassestandard' => $objPaare->startklassestandard, 
        'aktiv' => $objPaare->aktiv, 
        'aktivseit' => $objPaare->aktivseit, 
        'aktivbis' => $objPaare->aktivbis, 
      ); 
 
      if(strlen($objPaare->bild) == 0) 
      { 
        $newArr['bild'] = '/system/modules/gw_turnierpaare/icons/default.png'; 
      } 
      else 
      { 
        $newArr['bild'] = $this->getImage($objPaare->bild, '30', '30'); 
      } 
 
      $arrPaare[] = $newArr; 
    } 
    $this->Template->paare = $arrPaare; 
    } 
}

Wir leiten von Module ab, und $strTemplate enthält den Namen des Templates, welches wir füllen wollen. Die Funktion, die die Werte für das Template liefert, muss compile() heißen.

Wir holen uns alle Turnierpaardatensätze aus der Datenbank, sortiert nach den Nachnamen (andere Sortierungen und Filter werden später hinzugefügt!), durchlaufen diese in einer Schleife und füllen pro Eintrag ein Array $newArr mit den Werten der Datenbankfelder.

Das bild-Feld wird anders behandelt: ist es leer (also kein Bild ausgewählt), wird als Bild-URL ein Default-Bild übergeben, was ich von Hand zum icons-Unterverzeichnis hinzufüge (das benutzte Bild hänge ich hier an). Falls ein Bild angegeben wurde, hole ich mir über die in TL eingebaute getImage()-Funktion ein Thumbnail des Bildes, was maximal 30 mal 30 Pixel groß ist.

Dann wird das Array, was die Daten eines Paares enthält, zum Array mit allen Paardaten hinzugefügt, und ganz am Ende die Template-Variable paare mit unserem Ergebnis (also den Daten aller Paare in der Liste) gefüllt.

Nun das Ausgabetemplate system/modules/gw_turnierpaare/templates/gw_turnierpaarliste.tpl:

<div class="<?php echo $this->class; ?>"<?php echo $this->cssID; ?><?php if ($this-
>style): ?> style="<?php echo $this->style; ?>"<?php endif; ?>>
<?php if ($this->headline): ?>
<<?php echo $this->hl; ?>><?php echo $this->headline; ?></<?php echo $this->hl; ?>>
<?php endif; ?>
<table cellpadding="4" cellspacing="0" summary="Turnierpaarliste">
  <thead>
    <tr>
      <th>&nbsp;</th>
      <th>Name</th>
      <th>Startgruppe</th>
      <th>Std</th>
      <th>Lat</th>
      <th>Aktiv seit</th>
      <th> Aktiv bis</th>
    </tr>
  </thead>
  <tbody>
<?php foreach ($this->paare as $paar): ?>
  <tr<?php if($paar['aktiv'] != '1') { echo ' style="color: #888;"'; } ?>>
  <td>
  <img src="<?php echo $paar['bild']; ?>">
  </td>
  <td><?php echo $paar['partnernachname']; ?>
<?php if($paar['partnervorname']): ?>
<?php   echo ', '.$paar['partnervorname']; ?>
<?php endif; ?>
<?php if($paar['partnerinnachname']): ?>
<?php   echo ' und '.$paar['partnerinnachname']; ?>
<?php   if($paar['partnerinvorname']): ?>
<?php     echo ', '.$paar['partnerinvorname']; ?>
<?php   endif; ?>
<?php endif; ?>
  </td>
  <td><?php echo $paar['startgruppe']; ?>
  </td>
  <td><?php echo $paar['startklassestandard']; ?>
  </td>
  <td><?php echo $paar['startklasselatein']; ?>
  </td>
  <td><?php echo $paar['aktivseit']; ?>
  </td>
  <td><?php echo $paar['aktivbis']; ?>
  </td>
  </tr><?php endforeach; ?>
  </tbody>
</table>
</div>

Den Teil bis zum Beginn der Table habe ich aus einem anderen Template übernommen, und enthält den "Standardheader" mit der Möglichkeit, spezielle Klassen, IDs und Styles anzugeben. Auch eine Überschrift wird zugelassen, falls sie gesetzt ist.

In der Tabelle selbst wird ein Kopfbereich definiert mit den Spaltenüberschriften.

Dann werden alle Paare in der Paarliste (Variable $this->paare) durchlaufen. Falls das Paar NICHT aktiv ist, setze ich einen style für die Tabellenzeile (graue Schrift). Das ist so nicht "sauber" und wird auch so nicht bleiben, sondern durch richtiges CSS-Markup ersetzt. Erstmal dient es zur Visualisierung.

Aus den Namen von Herr und Dame wird ein "schöner" Namensstring zusammengebaut und ausgegeben. Die restlichen Felder werden ziemlich straight-forward ausgegeben.

Nun wären wir eigentlich "fast" fertig. Aber um unser neues Frondendmodul nutzen zu können, muss es im Backend unter "Module" angelegt werden. Das übernimmt die Backend-Klasse tl_module, und die weiss noch nichts detailliertes über unser neues Frontendmodul.

Wir müssen die DCA-Konfiguration für die Backend-Klasse tl_module so erweitern, dass die richtige Palette angezeigt wird, wenn bei Modul-Typ unser neues Frontendmodul ausgewählt wird. Dafür legen wir in system/modules/gw_turnierpaare/dca/ eine neue Datei tl_module.php an. Dort können wir die Definition erweitern. Das tun wir NICHT im tl_module-Backendmodul selbst. Da die DCA-Definitionen aller Extensions nacheinander eingelesen werden (und auf jeden Fall nach Frontend und Backend) können wir den fehlenden Eintrag für tl_module bei uns im Modul nachholen.

In die tl_module.php kommt:

<?php 
// Add a palette to tl_module 
$GLOBALS['TL_DCA']['tl_module']['palettes']['gw_turnierpaarliste'] = 'name,type,headline;align,space,cssID'; 
?>

Wenn in der Modulverwaltung in der Dropdown-Liste der zur Verfügung stehenden Module unseres (gw_turnierpaare) ausgewählt wird, wird diese Palette aktiviert, und als Modul-Optionen Name, Typ und Überschrift, Ausrichtung, Abstände und css-Optionen angezeigt. Später werden wir hier noch weitere Optionen einfügen.

Der letzte Key der Definition gw_turnierpaarliste muss die ID unseres Moduls sein, so wie in config/config.php definiert. Hier hatte ich zuerst tl_gw_turnierpaare benutzt - funktioniert nicht!

Jetzt können wir das neue Modul in der Modulverwaltung anlegen:

Modul Auswahl

Modul Tunierpaarliste

Hier sehen wir unsere Frontendmodule (das zweite kommt noch) in der Auswahlliste und bei Selektion des oberen Moduls die geänderte Palette (durch die Erweiterung des DCAs von tl_module). align scheint aber irgendwie nicht zu funktionieren. Ich ignoriere das erstmal.

Jetzt können wir das Modul einem Artikel hinzufügen, und bei mir sieht es dann so aus:

Erste Frontend Ausgabe

Gut, das Icon ist auf meinem Hintergrund noch nicht "hübsch", aber die zugrunde liegende Funktionalität (Default-Bild wenn keins gesetzt), usw... ist erkennbar. Auch die Thumbnailerstellung eines Paarbildes funktioniert, und nicht-aktive Paare werden grau dargestellt.

Damit genug für heute, ein erstes Ergebnis ist erreicht, aber das Frontendmodul wird noch deutlich aufgebohrt werden. In den nächsten Folgen ;-).

Ein wenig Finetuning

Zunächst mal habe ich mir die Palettendefinitionen in system/modules/backend/dca/tl_module.php angeschaut und festgestellt, dass der von mir benutzte Code aus einem Tutorial wohl etwas veraltet ist.

Ich orientiere mich an den anderen Einträgen und ändere meine Palettendefinition für die Modul-Verwaltung in system/modules/gw_turnierpaare/dca/tl_module.php auf:

<?php 
// Add a palette to tl_module 
$GLOBALS['TL_DCA']['tl_module']['palettes']['gw_turnierpaarliste'] = '{title_legend},name,headline,type;{protected_legend:hide},protected;
{expert_legend:hide},guests,cssID,space'; 
?>

Damit haben wir schöne Palettenüberschriften und den "Standardsatz" an Eigenschaften für Module.

Dann hatte ich das hier entdeckt: Auf den aktiven Datensatz im DCA zugreifen, und erinnerte mich an den save_callback für das Passwort-Feld der Paare, der genau sowas (Datensatz mit aktueller ID aus Datenbank einlesen) macht. Da ich sowieso nur 2.8 einsetze, wo das Feature des activeRecord verfügbar ist, klang das gut, und ich wollte es so umsetzen.

Aber: Der activeRecord enthält im save_callback wirklich die aktuellen Werte der Felder in der Eingabemaske. Im Falle des Passwortfelds also den leeren String, wenn nichts eingegeben wurde, bzw. das neue Klartextpasswort. Im save_callback brauche ich aber das alte, in der DB vorliegende Passwort (um den salt dort herauszuholen). Das geht mit dem activeRecord nicht, und ich muss mit der alten Methode, das Feld aus der Datenbank zu holen, leben. Wenn man aber wirklich die aktuell in der Maske vorliegenden Felder benötigt, ist der activeRecord bestimmt ein super Feature.

Diskussion

user: Toflar

Als kleine Ergänzung. Ich finde das passt gerade schön hier rein:

Oftmals muss man für ältere TL Versionen mit dem Code ein bisschen anders umgehen. Aber man möchte die Erweiterung trotzdem für mehrere Versionen freigeben. Dann muss man halt an diversen Orten die TL-Version prüfen:

if(version_compare(VERSION . '.' . BUILD, '2.8.0', '<')) 
{ 
   // mach für Versionen unter 2.8.0 das 
} 
else 
{ 
   // ab Version 2.8.0 mach das 
}
Ansichten
Meine Werkzeuge

Contao Community Documentation

God: "what is your job?"
me: "i am a software developer ... i develop websites with Contao 3"
God: "sounds cool, what are you working on today? Web sockets? Ajax? HTML5 video streaming?"
me: "no, i am trying to send an email ...."

Leo Unglaub
Navigation
Verstehen
Verwenden
Entwickeln
Verschiedenes
Werkzeuge