<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="https://de.contaowiki.org/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
		<id>https://de.contaowiki.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Schnippsel</id>
		<title>Contao Community Documentation - Benutzerbeiträge [de]</title>
		<link rel="self" type="application/atom+xml" href="https://de.contaowiki.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Schnippsel"/>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Spezial:Beitr%C3%A4ge/Schnippsel"/>
		<updated>2026-05-02T10:40:36Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.22.6</generator>

	<entry>
		<id>https://de.contaowiki.org/TEE-06_Backend_Callbacks_und_Subpaletten</id>
		<title>TEE-06 Backend Callbacks und Subpaletten</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-06_Backend_Callbacks_und_Subpaletten"/>
				<updated>2010-07-08T22:57:18Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: hat „TEE-06 Callbacks und Subpaletten“ nach „TEE-06 Backend Callbacks und Subpaletten“ verschoben:&amp;amp;#32;Die Bennenungssystematik war nicht eingehalten.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Von Callbacks und Subpaletten=&lt;br /&gt;
Nachdem auch das englische Sprachfile fertig ist, geht es nun an die letzte fehlende Funktionalität der Backend-Maske. Zunächst gibt es aber noch einige Detailkorrekturen.&lt;br /&gt;
&lt;br /&gt;
Da MySQL keinen ''Boolean''-Datentyp bietet, hatte ich die Felder, die nur true/false sein können, als int(1) angelegt, mit den möglichen Werten 0/1. Das klappt auch prinzipiell, die Stati der Checkboxen werden gespeichert und wieder aus der Datenbank ausgelesen, aber ein Problem zeigt sich, wenn man nach so einem Feld filtern will: Ich will nach dem ''aktiv''-Feld filtern können. Häufig sind die die &amp;quot;aktiven&amp;quot; Turnierpaare von Interesse, die nicht mehr aktiven verstopfen aber die Liste.&lt;br /&gt;
&lt;br /&gt;
Wählt man dieses Feld nun als Filter-Feld aus, werden in der DropDown-Liste als Filtermöglichkeiten aber nur &amp;quot;Ja&amp;quot; und nochmals &amp;quot;Ja&amp;quot; angezeigt. Das Filtern klappt damit auch, bei dem einen &amp;quot;Ja&amp;quot; werden nur die aktiven Paare angezeigt, beim anderen &amp;quot;Ja&amp;quot; die inaktiven. Aber das ist natürlich nicht so gewollt.&lt;br /&gt;
&lt;br /&gt;
Durch Abschauen bei anderen Extensions bin ich darauf gekommen, die Checkbox-Felder durch ''char(1)'' statt ''int(1)'' abzubilden. Das klappt genau so gut, und auch das Filtern funktioniert mit &amp;quot;Ja&amp;quot; und &amp;quot;Nein&amp;quot;. Alle ''int(1)''-Felder wurden entsprechend in ''char(1)'' verändert. Nach dem Anpassen der ''database.sql'' muss natürlich das Install-Tool ausgeführt werden, um die Änderungen in der Datenbank durchzuführen.&lt;br /&gt;
&lt;br /&gt;
Die ''database.sql'' sieht jetzt so aus:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE `tl_gw_turnierpaare` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `partnernachname` varchar(64) NOT NULL default '',&lt;br /&gt;
  `partnervorname` varchar(64) NULL default NULL,&lt;br /&gt;
  `partnerinnachname` varchar(64) NULL default NULL,&lt;br /&gt;
  `partnerinvorname` varchar(64) NULL default NULL,&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '',&lt;br /&gt;
  `startklasselatein` varchar(12) NULL default NULL,&lt;br /&gt;
  `startklassestandard` varchar(12) NULL default NULL,&lt;br /&gt;
  `aktiv` char(1) NOT NULL default '',&lt;br /&gt;
  `aktivseit` int(4) NULL default NULL,&lt;br /&gt;
  `aktivbis` int(4) NULL default NULL,&lt;br /&gt;
  `resetpassword` char(1) NULL default '',&lt;br /&gt;
  `password` varchar(64) NULL default NULL,&lt;br /&gt;
  `bild` varchar(255) NULL default NULL,&lt;br /&gt;
  `anschrift` text NULL,&lt;br /&gt;
  `zeigeanschrift` char(1) NOT NULL default '',&lt;br /&gt;
  `telefon` varchar(32) NULL default NULL,&lt;br /&gt;
  `zeigetelefon` char(1) NOT NULL default '',&lt;br /&gt;
  `fax` varchar(32) NULL default NULL,&lt;br /&gt;
  `zeigefax` char(1) NOT NULL default '',&lt;br /&gt;
  `mobil` varchar(32) NULL default NULL,&lt;br /&gt;
  `zeigemobil` char(1) NOT NULL default '',&lt;br /&gt;
  `email` varchar(128) NULL default NULL,&lt;br /&gt;
  `zeigeemail` char(1) NOT NULL default '',&lt;br /&gt;
  `homepage` varchar(128) NULL default NULL,&lt;br /&gt;
  `zeigehomepage` char(1) NOT NULL default '',&lt;br /&gt;
  `beschreibung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer aufgepasst hat, dem ist auch noch ein neues Feld aufgefallen:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  `resetpassword` char(1) NULL default '',&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das werde ich gleich für das Aktivieren einer Subpalette benötigen. Der Inhalt des Feldes in der Datenbank wird später nicht gebraucht, aber leider muss das Feld vorhanden sein, um es so nutzen zu können, wie ich es vorhabe.&lt;br /&gt;
&lt;br /&gt;
Für das ''password''-Feld habe ich ich vor, dass ein dort eingegebenes Passwort SHA1-gehasht in der Datenbank abgelegt wird, nicht im Klartext. Dabei wird ein eventuell schon vorhandes Passwort natürlich überschrieben.&lt;br /&gt;
&lt;br /&gt;
Um Fehleingaben zu verhindern, möchte ich eine Checkbox anzeigen, die defaultmäßig &amp;quot;aus&amp;quot; ist. Erst wenn die Checkbox aktiviert ist, soll per AJAX das Passwortfeld angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Zunächst fügen die wir Definition für das Checkbox-Feld in die ''field''-Sektion des DCA-Records ein:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'resetpassword' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['resetpassword'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'default'                 =&amp;gt; '', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true, 'submitOnChange' =&amp;gt; true), &lt;br /&gt;
        ), &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''submitOnChange'' bewirkt, dass das Formular neu geladen wird, wenn das Feld angeklickt wird. nur dann wird das Passwortfeld nachgeladen.&lt;br /&gt;
&lt;br /&gt;
Dafür benötigen wir eine sogenannte &amp;quot;Subpalette&amp;quot;. Die Checkbox (bei mir &amp;quot;resetpassword&amp;quot;) muss als &amp;quot;__selector__&amp;quot; angegeben werden im DCA-Record:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array('resetpassword'), &lt;br /&gt;
...  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der ''default''-Sektion sieht die Palettendefinition so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                                  .'{aktiv_legend:hide},aktiv,aktivseit,aktivbis;{password_legend:hide},resetpassword;'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier steht also der Name der Subpalette. Der Name des Passwortfeldes steht hier nicht mehr. Das wird in der ''subpalettes''-Sektion angegeben:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Subpalettes &lt;br /&gt;
    'subpalettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'resetpassword'               =&amp;gt; 'password' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies bedeutet, dass das Feld ''password'' in die Subpalette ''resetpassword'' eingeblendet wird, wenn ''resetpassword'' aktiviert ist. Wird es deaktiviert, verschwindet die Subpalette wieder.    &lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_016.png]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_017.png]]&lt;br /&gt;
&lt;br /&gt;
Die Texte hierzu wurden in den Sprachfiles entsprechend erweitert und angepasst.&lt;br /&gt;
&lt;br /&gt;
Für beide Felder, ''resetpassword'' und ''password'', benötige ich besondere Funktionalitäten. ''resetpassword'' soll bei Öffnen der Backendmaske IMMER deaktiviert, das Passwort-Feld also versteckt sein - egal was in der Datenbank für das Feld steht. Dafür setze ich zunächst&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'default'                 =&amp;gt; '',  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
was dafür sorgt, dass beim Anlegen eines neuen Datensatzes die Checkbox deaktiviert ist. Und dann gibt es noch die Option ''load_callback'', in der eine Funktion angegeben werden kann, die beim Laden des Feldes aufgerufen wird (Zu den Details von Callbacks gleich mehr).&lt;br /&gt;
&lt;br /&gt;
Hier habe ich versucht, durch ''return &amp;lt;nowiki&amp;gt;' '&amp;lt;/nowiki&amp;gt;;'' immer den Defaultwert zurückzugeben. Leider klappt das nicht richtig, wenn der Datensatz mit &amp;quot;speichern&amp;quot; gespeichert wird, aber geöffnet bleibt. Obwohl die Checkbox dann deaktiviert dargestellt wird, bleibt das Passwort-Feld trotzdem angezeigt und wird nicht versteckt. Erst durch manuelles Aktivieren und erneutes Deaktivieren verschwindet das Passwortfeld wieder. Ich weiß nicht, ob das ein Bug oder gewollt ist, zumindest gefiel es mir nicht.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Versuch scheiterte mit dem ''save_callback'': also einer Funktion, die aufgerufen wird, bevor das Feld in die Datenbank gespeichert wird. Hier versuchte ich ebenfalls durch ein ''return &amp;lt;nowiki&amp;gt;' '&amp;lt;/nowiki&amp;gt;;'' zu erzwingen, dass immer ein deaktiviertes Feld gespeichert wird, und damit auch beim erneuten Anzeigen des Formulars deaktiviert bleibt.&lt;br /&gt;
&lt;br /&gt;
Das funktioniert optisch auch sehr gut. Leider werden dann aber keine Eingaben im Passwort-Feld gespeichert.&lt;br /&gt;
&lt;br /&gt;
Der Grund wird sehr wahrscheinlich sein, dass der ''save_callback'' auf dem ''resetpassword''-Feld ausgeführt wird, bevor der Input im ''password''-Feld verarbeitet wird. Mein ''Save-Callback'' deaktiviert die Checkbox, und damit auch die Subpalette, und das Feld in der Subpalette wird gar nicht mehr ausgewertet oder gespeichert. Auch die Reihenfolge der Felddefinitionen hat darauf keinen Einfluss, es kommt wohl auf die Reihenfolge in der Palettendefinition an, und die kann ich nicht umdrehen.&lt;br /&gt;
&lt;br /&gt;
An der Stelle war tiefe Frustration angesagt, aber ich habe das Problem anders lösen können. Beim ''resetpassword''-Feld werden jetzt keine Callbacks verwendet.&lt;br /&gt;
&lt;br /&gt;
Dafür aber beim ''password''-Feld, was jetzt in der Definition so aussieht:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'password' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['password'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength' =&amp;gt; 64), &lt;br /&gt;
            'load_callback'           =&amp;gt; array(array('tl_gw_turnierpaare','password_load_callback')), &lt;br /&gt;
            'save_callback'           =&amp;gt; array(array('tl_gw_turnierpaare','password_save_callback')) &lt;br /&gt;
        ), &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Durch diese Definition wird beim Laden des Feldes die Funktion ''password_load_callback'' und beim Speichern ''password_save_callback'' aufgerufen, die sich in der Klasse ''tl_gw_turnierpaare'' befinden. Diese Klasse lege ich in der DCA-Definitions-Datei ''/modules/gw_turnierpaare/dca/tl_gw_turnierpaare.php'' an.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class tl_gw_turnierpaare extends Backend &lt;br /&gt;
{ &lt;br /&gt;
    /** &lt;br /&gt;
     * Import the back end user object &lt;br /&gt;
     */ &lt;br /&gt;
    public function __construct() &lt;br /&gt;
    { &lt;br /&gt;
        parent::__construct(); &lt;br /&gt;
        $this-&amp;gt;import('BackendUser', 'User'); &lt;br /&gt;
    } &lt;br /&gt;
   &lt;br /&gt;
  public function password_load_callback() &lt;br /&gt;
  { &lt;br /&gt;
 ... &lt;br /&gt;
 } &lt;br /&gt;
   &lt;br /&gt;
  public function password_save_callback($var, $dc) &lt;br /&gt;
  { &lt;br /&gt;
... &lt;br /&gt;
  } &lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Gerüst habe ich mir bei anderen Extensions abgeschaut, es scheint zumindest klug zu sein, von ''Backend'' zu erben, und den Konstruktur zu überschreiben. Vielleicht ist es auch nicht nötig, ich habe es nicht probiert. Ob der ''load_callback'' Parameter übergeben bekommt, weiss ich nicht, aber ich benötige keinen Parameter.&lt;br /&gt;
&lt;br /&gt;
Der ''save_callback'' erhält den Wert des Feldes, das gespeichert werden soll ($var), und den DataContainer ($dc), der zu dem Formular gehört. Meist (wie auch hier) ist es DC_Table, der DataContainer für Datenbanktabellen.&lt;br /&gt;
&lt;br /&gt;
Mein ''password''-Feld in der Datenbank wird den SHA1-Hash, also einen langen String unverständlicher hexadezimaler Zahlen enthalten. Es nützt nichts, wenn ich den im Backend im Passwort-Feld anzeige. Dort will der Admin Klartext-Passwörter eingeben. Im Load-Callback setze ich den Wert des ''password''-Felds also auf einen leeren String, egal was in der Datenbank steht:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  public function password_load_callback() &lt;br /&gt;
  { &lt;br /&gt;
    // Passwort-Feld immer leer anzeigen (Damit der User SHA1-Hash nicht sieht) &lt;br /&gt;
    return ''; &lt;br /&gt;
  } &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit wird der User schon mal nicht vom &amp;quot;Müll&amp;quot; aus der Datenbank belästigt. Umgekehrt müssen wir aber nicht das Klartext-Passwort, sondern den Hash in die Datenbank schreiben. Das macht der ''save_callback'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  public function password_save_callback($var, $dc) &lt;br /&gt;
  { &lt;br /&gt;
    // Kein neues PW angegeben: Feld nicht ändern &lt;br /&gt;
    if(strlen($var) &amp;lt; 1) return ''; &lt;br /&gt;
    // Aktuellen Datensatz aus DB holen &lt;br /&gt;
    $row = $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;SELECT * FROM tl_gw_turnierpaare WHERE id=?&amp;quot;) &lt;br /&gt;
                              -&amp;gt;execute($dc-&amp;gt;id); &lt;br /&gt;
    // PW in Passwort und Salt aufspalten &lt;br /&gt;
    list($strPassword, $strSalt) = explode(':', $row-&amp;gt;password); &lt;br /&gt;
    // Falls kein Salt vorhanden, dann erzeugen &lt;br /&gt;
        if (!strlen($strSalt)) &lt;br /&gt;
        { &lt;br /&gt;
            $strSalt = substr(md5(uniqid('', true)), 0, 23); &lt;br /&gt;
        } &lt;br /&gt;
    // SHA1-Hash aus Salt+neuem Passwort berechnen, Salt anhängen &lt;br /&gt;
    $pwd = sha1($strSalt . $var) . ':' . $strSalt; &lt;br /&gt;
    // Das resetpassword-Feld löschen &lt;br /&gt;
    $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;UPDATE tl_gw_turnierpaare SET resetpassword='' WHERE id=?&amp;quot;) &lt;br /&gt;
                              -&amp;gt;executeUncached($dc-&amp;gt;id); &lt;br /&gt;
    return $pwd; &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls kein Passwort angegeben wurde, macht der ''save_callback'' garnichts, und gibt einen leeren String zurück. &lt;br /&gt;
&lt;br /&gt;
Das Feld ''Id'' des DataContainers enthält die ''id'' des aktuellen Datensatzes in der Datenbank. Um den Hash berechnen zu können, benötige ich das &amp;quot;alte&amp;quot; Passwort in der Datenbank. Darum hole ich mir erstmal den gesamten Datensatz mit der ID ab.&lt;br /&gt;
&lt;br /&gt;
Die Hash-Erzeugung habe ich mir beim File ''/system/libraries/User.php'' abgeschaut und funktioniert genauso wie in der Userverwaltung von TYPOlight: Der Hash wird zusammen mit einem &amp;quot;Salt&amp;quot; erzeugt, der zusammen mit dem Hash (durch Doppelpunkt getrennt) im ''password''-Feld abgespeichert wird. Existiert noch kein Salt, wird er erzeugt. Existiert der Salt schon, wird er weiterverwendet (und dafür muss ich das alte Passwort aus der Datenbank auslesen - um an den evtl. schon vorhandenen Salt zu kommen). Die Hash-Erzeugung läuft dann ziemlich straight-forward ab.&lt;br /&gt;
&lt;br /&gt;
Und fast ganz am Ende nochmal der Knackpunkt: Hier setze ich das ''resetpassword''-Feld in der Datenbank auf ''. &lt;br /&gt;
&lt;br /&gt;
Das (und leider nur das) sorgt in allen Fällen dafür, dass beim Öffnen von Datensätzen die Subpalette für das ''password''-Feld geschlossen ist.&lt;br /&gt;
&lt;br /&gt;
Abschließend gebe ich den berechneten Hash zurück. Er wird dann in die Datenbank eingetragen.&lt;br /&gt;
&lt;br /&gt;
Wichtiger Hinweis noch: ''load_callback'' und ''save_callback'' müssen doppelt geschachtelte Arrays sein, weil es mehrere Callbacks geben kann, die nacheinander aufgerufen werden, der Feldwert wird jeweils durch alle durchgeschleust. Falls man aber z.B. einen ''onSubmitCallback'' für das ganze Formular vorgeben möchte, ist das nur ein einfaches Array mit Klassennamen und Methodenname, weil es hier nur einen Callback gibt. Das ist so leider in der Referenz der möglichen Callbacks nicht dokumentiert, und hat mir kurz graue Haare beschert.&lt;br /&gt;
&lt;br /&gt;
Damit ist das Backend-Modul für die Turnierpaar-Tabelle erstmal fertig.&lt;br /&gt;
&lt;br /&gt;
Weiter wird es dann (endlich) mit dem Frontendmodul für die Turnierpaarliste gehen.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-05_Backend_Language_Files</id>
		<title>TEE-05 Backend Language Files</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-05_Backend_Language_Files"/>
				<updated>2010-07-08T22:56:18Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: hat „TEE-05 Language Files“ nach „TEE-05 Backend Language Files“ verschoben:&amp;amp;#32;Die Bennenungssystematik war nicht eingehalten.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Language Files=&lt;br /&gt;
Nun geht es an die Sprachfiles, um das Backend-Modul &amp;quot;hübsch&amp;quot; zu machen.&lt;br /&gt;
&lt;br /&gt;
Ich demonstriere es für die deutschen Sprachfiles im ''/system/modules/gw_turnierpaare/languages/de/''-Verzeichnis. Englisch geht genau analog :-).&lt;br /&gt;
&lt;br /&gt;
Zunächst definieren wir die Namen der Back- und Frontendmodule, und einen kurzen Erklärungstext dazu. Das wird in ''modules.php'' gemacht:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Back end modules &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['gw_turnierpaare'] = array('Turnierpaare', 'Verwaltung der Turnierpaare und der Meldeliste.'); &lt;br /&gt;
/** &lt;br /&gt;
 * Front end modules &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['FMD']['gw_turnierpaarliste'] = array('Turnierpaarliste', 'Dieses Modul zeigt die Turnierpaarliste an'); &lt;br /&gt;
$GLOBALS['TL_LANG']['FMD']['gw_meldeliste'] = array('Meldeliste', 'Dieses Modul zeigt die Meldeliste an');&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Bezeichner hinter 'MOD' und 'FMD' müssen die sein, dir wir im config/config.php der Extension definiert haben. Die entsprechenden Texte für die beiden geplanten Frontendmodule habe ich hier auch schon mal eingetragen, auch wenn es die Module noch nicht gibt...&lt;br /&gt;
&lt;br /&gt;
Die Texte für die Backendfelder sind in tl_gw_turnierpaare.php definiert, entsprechend dem Namen der Datenbanktabelle. Die in der DCA-Record-Definition deklarierten Felder müssen wir mit Text füllen. Das ist ziemlich straight-forward:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Fields &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname']    = array('Nachname des Partners', 'Bitte den Nachnamen des (m&amp;amp;auml;nnlichen) Partners eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnervorname']     = array('Vorname des Partners', 'Bitte den Vornamen des (m&amp;amp;auml;nnlichen) Partners eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinnachname']  = array('Nachname der Partnerin', 'Bitte den Nachnamen des (weiblichen) Partners eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinvorname']   = array('Vorname der Partnerin', 'Bitte den Vornamen des (weiblichen) Partners eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startgruppe']        = array('Startgruppe', 'Bitte die Startgruppe (JUG, HGR, SEN, ...) des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklasselatein']  = array('Startklasse Latein', 'Bitte die Startklasse (Latein) des Paares eingeben. Kein Lateinstartbuch = &amp;quot;-&amp;quot;'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklassestandard'] = array('Startklasse Standard', 'Bitte die Startklasse (Standard) des Paares eingeben. Kein Standardstartbuch = &amp;quot;-&amp;quot;'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktiv']              = array('Aktiv', 'Bitte angeben, ob das Paar noch aktiv ist'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivseit']          = array('Aktiv seit', 'Bitte Jahreszahl des ersten Starts angeben (z.B. 2005)'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivbis']           = array('Aktiv bis', 'Bitte Jahreszahl des letzten Starts angeben, wenn das Paar nicht mehr aktiv is&lt;br /&gt;
t (z.B. 2008)'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['password']           = array('Passwort', 'Bitte ein Passwort f&amp;amp;uuml;r das Paar anlegen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeanschrift']     = array('Anschrift anzeigen', 'Anschrift in der Visitenkarte sichtbar?'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['anschrift']          = array('Anschrift', 'Bitte Anschrift des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigetelefon']       = array('Telefonnummer anzeigen', 'Telefonnummer in der Visitenkarte sichtbar?'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['telefon']            = array('Telefonnummer', 'Bitte Telefonnummer des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigefax']           = array('Faxnummer anzeigen', 'Faxnummer in der Visitenkarte sichtbar?'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['fax']                = array('Faxnummer', 'Bitte Faxnummer des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigemobil']         = array('Mobilnummer anzeigen', 'Mobilnummer in der Visitenkarte sichtbar?'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['mobil']              = array('Mobilnummer', 'Bitte Mobilnummer des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeemail']         = array('Email-Adresse anzeigen', 'Email-Adresse in der Visitenkarte sichtbar?'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['email']              = array('Email-Adresse', 'Bitte Emailadresse des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigehomepage']      = array('Homepage-Adresse anzeigen', 'Homepage-Adresse in der Visitenkarte sichtbar?'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['homepage']           = array('Homepage-Adresse', 'Bitte Homepage-Adresse des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['beschreibung']       = array('Beschreibungstext', 'Bitte Beschreibungstext des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['bild']               = array('Paarbild', 'Bitte ein Paarbild ausw&amp;amp;auml;hlen'); &lt;br /&gt;
/** &lt;br /&gt;
 * Reference &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['name_legend']          = 'Namen'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['classes_legend']       = 'Startdaten'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktiv_legend']         = 'Aktiv'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['password_legend']      = 'Passwort'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['contact_legend']       = 'Kontakt'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['beschreibung_legend']  = 'Beschreibung'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['bild_legend']          = 'Bild'; &lt;br /&gt;
/** &lt;br /&gt;
 * Buttons &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['new']    = array('Neues Paar', 'Ein neues Turnierpaar anlegen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['edit']   = array('Editieren', 'Das Turnierpaar editieren'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['copy']   = array('Paar kopieren', 'Das Turnierpaar in die Zwischenablage kopieren'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['delete'] = array('Paar löschen', 'Das Turnierpaar aus der Liste entfernen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['show']   = array('Details', 'Die Detailansicht des Turnierpaars anzeigen');&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unterschieden werden die Texte für die Eingabefelder, die aus Überschrift/Bezeichner für das Feld und dem darunter angezeigten Beschreibungstext bestehen, den Texten für Palettenüberschriften (mittlerer Teil) und den Texten für die Buttons in den Masken (letzter Teil). Umlaute müssen HTML-üblich durch ihre Ersatzcodes (ä = &amp;amp;auml; usw.) dargestellt werden. Die Beschreibungstexte sollten auch nicht zu lang werden.&lt;br /&gt;
&lt;br /&gt;
Ich habe in der DCA-Definition auch Referenzen auf Sprach-Strings für die Eigenschaft ''explanation'' angegeben, z.B. so:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname_explanation'],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
allerdings habe ich nicht erkennen können, wo das benutzt wird. Vielleicht nur in bestimmten Situatuionen/Konfigurationen. Ich habe all diese Referenzen bei jedem Feld aus meiner DCA-Konfiguration also wieder entfernt.&lt;br /&gt;
&lt;br /&gt;
Die Backend-Maske sieht jetzt so aus:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_015.png]]&lt;br /&gt;
&lt;br /&gt;
==Diskussion==&lt;br /&gt;
'''user: deerwood'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Zitat:&lt;br /&gt;
Umlaute müssen HTML-üblich durch ihre Ersatzcodes (ä = &amp;amp;auml; usw.) dargestellt werden &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Nein. UTF8 Zeichen/Editoren sind heutzutage angesagt   . Z.B. Notepad++ oder Eclipse oder ... oder ...&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
vielen Dank für den Hinweis. Ich nutze PSPad, den ich eigentlich als &amp;quot;vernünftigen&amp;quot; Editor ansehe, aber trotzdem stand der Zeichensatz auf &amp;quot;ANSI&amp;quot;. Mit UTF8 geht es natürlich auch mit Umlauten ;-). Da muss ich in Zukunft mehr drauf achten.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-00_Vorbemerkung</id>
		<title>TEE-00 Vorbemerkung</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-00_Vorbemerkung"/>
				<updated>2010-07-07T21:44:58Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung / Vorbemerkungen der Wiki-Autoren&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Vorbemerkungen=&lt;br /&gt;
* Die Artikel nehmen einen sehr ausführlichen Forumsthread aus dem Contao-Community-Forum ''Allgemeine Infos für Third-Party Extensions -&amp;gt; Entwickler-Tutorials'' auf, der unter dem Titel ''Tagebuch einer Extension-Entwicklung'' von dl1ely (Stefan) verfasst wurde. &lt;br /&gt;
&lt;br /&gt;
* Sie finden den Thread hier: [[http://www.contao-community.de/showthread.php?6570-Tagebuch-einer-Extension-Entwicklung Original Forumsbeitrag]]. Dort können Sie die Diskussion weiterführen. Ob künftige Forumsbeiträge hier eingearbeitet werden, ist nicht sichergestellt.&lt;br /&gt;
&lt;br /&gt;
* Die Originalbeiträge wurden redaktionell leicht überarbeitet. Dabei wurden neben forumsspezifischen Besonderheiten auch Überleitungen, Anrede- und Grußformeln, Bewertungen (&amp;quot;Ich finde das Tutorial gaaaanz toll!&amp;quot;) u.ä. entfernt.&lt;br /&gt;
&lt;br /&gt;
* An einigen Stellen wurden kleine Ergänzungen eingefügt.&lt;br /&gt;
&lt;br /&gt;
* Entgegen den Wiki-Gepflogenheiten sind die Artikel in der Ich-Form gehalten, da es sich um einen Erfahrungsbericht handelt.&lt;br /&gt;
&lt;br /&gt;
* Im Großen und Ganzen orientiert sich das Tutorial an der TL/contao-Systematik und besteht daher aus den zwei Blöcken ''Backend'' und ''Frontend''. Eine strikte thematische Gliederung ist hier allerdings nicht möglich. Als Erfahrungsbericht glänzt das Tutorial ja gerade dadurch, dass die im Verlauf der Entwicklung auftretenden Probleme und Fragestellungen abgearbeitet werden und entsprechende Rücksprünge an vorherige, bereits erledigt geglaubte Bearbeitungsschritte erfordern. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Und so ist das Tutorial aufgebaut:&lt;br /&gt;
&lt;br /&gt;
*TEE-00 Vorbemerkungen&lt;br /&gt;
&lt;br /&gt;
*[[TEE-01 Einleitung|TEE-01 Einleitung]]&lt;br /&gt;
*[[TEE-02 Extension Creator|TEE-02 Extension Creator]]&lt;br /&gt;
*[[TEE-03 Backend BE-Modul und SQL|TEE-03 Backend BE-Modul und SQL]]&lt;br /&gt;
*[[TEE-04 Backend DCA|TEE-04 Backend DCA]]&lt;br /&gt;
*[[TEE-05 Backend Language Files|TEE-05 Backend Language Files]]&lt;br /&gt;
*[[TEE-06 Backend Callbacks und Subpaletten|TEE-06 Backend Callbacks und Subpaletten]]&lt;br /&gt;
*[[TEE-07 Frontend Simpel-Version|TEE-07 Frontend Simpel-Version]]&lt;br /&gt;
*[[TEE-08 Frontend Parametrisierung|TEE-08 Frontend Parametrisierung]]&lt;br /&gt;
*[[TEE-09 Frontend Detailliste|TEE-09 Frontend Detailliste]]&lt;br /&gt;
*[[TEE-10 Frontend Feinschliff|TEE-10 Frontend Feinschliff]]&lt;br /&gt;
*[[TEE-11 Backend Zweite Tabelle|TEE-11 Backend Zweite Tabelle]]&lt;br /&gt;
*[[TEE-12 Backend Callback-Magie|TEE-12 Backend Callback-Magie]]&lt;br /&gt;
*[[TEE-13 Frontend Meldeliste|TEE-13 Frontend Meldeliste]]&lt;br /&gt;
*[[TEE-14 Downloads|TEE-14 Downloads]]&lt;br /&gt;
*[[TEE-15 Werkzeuge|TEE-15 Werkzeuge]]&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-13_Frontend_Meldeliste</id>
		<title>TEE-13 Frontend Meldeliste</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-13_Frontend_Meldeliste"/>
				<updated>2010-07-07T21:37:13Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}   =Fron…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Frontendmodul Meldeliste=&lt;br /&gt;
So, weiter geht es mit dem vorerst letzten Schritt: Das Frontendmodul für die Meldeliste. Besondere Herausforderungen sind hier die Möglichkeit der Verknüpfung einzelner Einträge mit dem Frontendmodul für die Turnierpaardetails, und eine konfigurierbare seitenweise Anzeige der Einträge der Meldeliste (Da diese im Lauf der Zeit sehr umfangreich werden kann).&lt;br /&gt;
&lt;br /&gt;
Die Klasse des Frontendmoduls heisst ''gwMeldeliste'', und da ich sie schon bei der Erstellung im ''Extension-Creator'' angegeben hatte, ist diese schon als Frontendmodul registriert. Trotzdem checken wir das nochmal in ''/system/modules/gw_turnierpaare/config.php'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Front end module &lt;br /&gt;
array_insert($GLOBALS['FE_MOD']['turnierpaare'], 0, array &lt;br /&gt;
( &lt;br /&gt;
    'gw_turnierpaarliste' =&amp;gt; 'gwTurnierpaarliste', &lt;br /&gt;
    'gw_meldeliste'       =&amp;gt; 'gwMeldeliste' &lt;br /&gt;
)); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Für die Konfiguration des Frontend-Moduls für die Darstellung benötige ich zwei Parameter: Die Anzahl der Datensätze pro Seite und die URL, auf die weitergeleitet werden soll, wenn man auf einen Tanzpaarnamen klickt (Das sollte eine URL sein, auf der das Frontendmodul der Turnierpaarliste eingebunden ist). Darum muss ''/system/modules/gw_turnierpaare/config/database.sql'' erweitert werden:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--&lt;br /&gt;
-- Extend table 'tl_module'&lt;br /&gt;
--&lt;br /&gt;
CREATE TABLE `tl_module` (&lt;br /&gt;
  `gw_tp_showonlyactive` char(1) NOT NULL default 'B',&lt;br /&gt;
  `gw_tp_couplesorting` char(1) NOT NULL default 'A',&lt;br /&gt;
  `gw_ml_pagesize` int(4) NOT NULL default '50',&lt;br /&gt;
  `gw_ml_coupledetails` varchar(255) NULL default NULL&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''gw_ml_pagesize'' ist also ein ''int'' mit maximal 4 Stellen, ''gw_ml_coupledetails'' ein ''string''.&lt;br /&gt;
&lt;br /&gt;
Damit die beim Anlegen des Moduls auch angezeigt und editiert werden können, müssen wir an das DCA von ''tl_module'' ran, also in ''/system/modules/gw_turnierpaare/dca/tl_module.php'' einfügen:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$GLOBALS['TL_DCA']['tl_module']['palettes']['gw_meldeliste'] = '{title_legend},name,headline,type;{size_legend},gw_ml_pagesize, gw_ml_coupledetails;&lt;br /&gt;
{protected_legend:hide},protected;{expert_legend:hide},guests,cssID,space'; &lt;br /&gt;
$GLOBALS['TL_DCA']['tl_module']['fields']['gw_ml_pagesize'] = array &lt;br /&gt;
( &lt;br /&gt;
    'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_module']['gw_ml_pagesize'], &lt;br /&gt;
    'default'                 =&amp;gt; '50', &lt;br /&gt;
    'exclude'                 =&amp;gt; true, &lt;br /&gt;
    'inputType'               =&amp;gt; 'text', &lt;br /&gt;
    'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;4, 'rgxp' =&amp;gt; 'digit', 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
); &lt;br /&gt;
$GLOBALS['TL_DCA']['tl_module']['fields']['gw_ml_coupledetails'] = array &lt;br /&gt;
( &lt;br /&gt;
    'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_module']['gw_ml_coupledetails'], &lt;br /&gt;
    'exclude'                 =&amp;gt; true, &lt;br /&gt;
    'inputType'               =&amp;gt; 'text', &lt;br /&gt;
    'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Zunächst legen wir die neue Palette an, in der neben einigen Standardfeldern unsere beiden neuen Datenbankfelder stehen, und anschließend definieren wir diese Felder im DCA. Für die ''pagesize'' nehme ich einen Default von 50, ansonsten sind die Optionen inzwischen wohlbekannt.&lt;br /&gt;
&lt;br /&gt;
Nun brauchen wir noch hübsche Labels für die neuen Felder im Backend. &lt;br /&gt;
&lt;br /&gt;
''/system/modules/gw_turnierpaare/languages/de/modules.php'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$GLOBALS['TL_LANG']['tl_module']['size_legend']     = 'Seitenlänge und Detail-URL'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_module']['gw_ml_pagesize'] = array('Meldungen pro Seite', 'Bitte geben Sie an, wieviele Meldungen pro Seite ausgegeben werden sollen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_module']['gw_ml_coupledetails'] = array('URL der Paar-Detailseite' , 'URL, auf der die Paardetails ausgegeben werden, z.B. /turnierpaarliste/info/');&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
Entsprechend die englische Variante natürlich genauso.&lt;br /&gt;
&lt;br /&gt;
Damit sind wir im Backend hier angekommen: &lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_35.png]]&lt;br /&gt;
&lt;br /&gt;
Nun das Frontendmodul ''/system/modules/gw_turnierpaare/gwMeldeliste.php'' :&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php if (!defined('TL_ROOT')) die('You can not access this file directly!'); &lt;br /&gt;
/** &lt;br /&gt;
 * Class gwMeldeliste  &lt;br /&gt;
 * &lt;br /&gt;
 * @copyright  (C) 2010  &lt;br /&gt;
 * @author     Stefan Pfeiffer  &lt;br /&gt;
 * @package    Controller &lt;br /&gt;
 */ &lt;br /&gt;
class gwMeldeliste extends Module &lt;br /&gt;
{ &lt;br /&gt;
    /** &lt;br /&gt;
     * Template &lt;br /&gt;
     * @var string &lt;br /&gt;
     */ &lt;br /&gt;
    protected $strTemplate = 'gw_meldeliste'; &lt;br /&gt;
    protected $strErrorTemplate = 'gw_meldeliste_error'; 	 &lt;br /&gt;
&amp;lt;/pre&amp;gt;	&lt;br /&gt;
&lt;br /&gt;
Zwei Templatenamen: Einer für die Ausgabe der Liste, der andere wenn etwas schiefgegangen ist...&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  public static $strPageKey = 'page'; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
Der URL-Bestandteil, der beim Blättern in der Liste unsere aktuelle Seite mitzählt. Mit 'page' also z.B. .../meldeliste/page/3.html um die dritte Seite anzeigen zu lassen.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    /** &lt;br /&gt;
     * Generate module &lt;br /&gt;
     */ &lt;br /&gt;
    protected function compile() &lt;br /&gt;
    { &lt;br /&gt;
        $moduleParams = $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;SELECT gw_ml_pagesize, gw_ml_coupledetails FROM tl_module WHERE id=?&amp;quot;) &lt;br /&gt;
                -&amp;gt;limit(1) &lt;br /&gt;
                -&amp;gt;execute($this-&amp;gt;id); &lt;br /&gt;
    $pagesize = $moduleParams-&amp;gt;gw_ml_pagesize; &lt;br /&gt;
     &lt;br /&gt;
    $this-&amp;gt;Template-&amp;gt;coupledetails = $moduleParams-&amp;gt;gw_ml_coupledetails; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
	 &lt;br /&gt;
Zunächst holen wir uns unsere beiden Modulparameter aus der Datenbank. die Detail-URL schreiben wir gleich ins Template, die ''pagesize'' merken wir uns erstmal.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    if ( strlen($this-&amp;gt;Input-&amp;gt;get(gwMeldeliste::$strPageKey)) ) &lt;br /&gt;
        { &lt;br /&gt;
      if(is_numeric($this-&amp;gt;Input-&amp;gt;get(gwMeldeliste::$strPageKey))) &lt;br /&gt;
      { &lt;br /&gt;
        $page = $this-&amp;gt;Input-&amp;gt;get(gwMeldeliste::$strPageKey); &lt;br /&gt;
      } &lt;br /&gt;
      else &lt;br /&gt;
      { &lt;br /&gt;
        // Error &lt;br /&gt;
        $this-&amp;gt;Template = new FrontendTemplate($this-&amp;gt;strErrorTemplate); &lt;br /&gt;
        return; &lt;br /&gt;
      } &lt;br /&gt;
        } &lt;br /&gt;
        else &lt;br /&gt;
        { &lt;br /&gt;
      $page = 0; &lt;br /&gt;
    } &lt;br /&gt;
    $this-&amp;gt;Template-&amp;gt;page = $page;  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls eine Seitenzahl in der URL angegeben, wird diese in ''$page'' gespeichert. Falls die Angabe nicht-numerisch ist, wird das Fehlertemplate ausgegeben. Und wenn keine Seitenzahl angegeben wird, tragen wir 0 ins Template ein.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $limit = &amp;quot; LIMIT &amp;quot;.($pagesize*$page).&amp;quot;,&amp;quot;.$pagesize; &lt;br /&gt;
         &lt;br /&gt;
    $testNextPage = $this-&amp;gt;Database-&amp;gt;execute(&amp;quot;SELECT * from tl_gw_meldungen ORDER BY datum DESC LIMIT &amp;quot;.($pagesize*($page+1)).&amp;quot;,1&amp;quot;); &lt;br /&gt;
    if($testNextPage-&amp;gt;numRows &amp;lt; 1) &lt;br /&gt;
    { &lt;br /&gt;
      $this-&amp;gt;Template-&amp;gt;nextpage = -1; &lt;br /&gt;
    } &lt;br /&gt;
    else &lt;br /&gt;
    { &lt;br /&gt;
      $this-&amp;gt;Template-&amp;gt;nextpage = $page+1; &lt;br /&gt;
    }  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier basteln wir uns das passende &amp;quot;LIMIT&amp;quot;-Statement für die aktuell ausgewählte Seite zusammen. Ausserdem machen wir einen Testselect auf die erste row der darauffolgenden Seite. Falls diese existiert, wird die Nummer der nächsten Seite ins Template geschrieben, ansonsten eine -1 als Hinweis fürs Template.&lt;br /&gt;
&lt;br /&gt;
Ich weiss, dass man diesen Check, ob eine weitere Seite existiert auch anders lösen kann, wahrscheinlich sogar eleganter. Aber erstmal funktioniert es :-).&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $arrMeldungen = array();  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier kommen die ganzen Datensätze des Ergebnis rein...&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $objMeldungen = $this-&amp;gt;Database-&amp;gt;execute(&amp;quot;SELECT * FROM tl_gw_meldungen ORDER BY datum DESC&amp;quot;.$limit); &lt;br /&gt;
     &lt;br /&gt;
    if($objMeldungen-&amp;gt;numRows == 0) &lt;br /&gt;
    { &lt;br /&gt;
      // Error &lt;br /&gt;
      $this-&amp;gt;Template = new FrontendTemplate($this-&amp;gt;strErrorTemplate); &lt;br /&gt;
      return; &lt;br /&gt;
    } &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
	 &lt;br /&gt;
Ergebnisdatensätze aus der DB holen - wenn keine gefunden wurden, dann Error-Template ausgeben.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    while($newArr = $objMeldungen-&amp;gt;fetchAssoc()) &lt;br /&gt;
    {&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
	 &lt;br /&gt;
Jede Row in ein assoziatives Array umwandeln...&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      $objPaar = $this-&amp;gt;Database-&amp;gt;execute(&amp;quot;SELECT * FROM tl_gw_turnierpaare WHERE id=&amp;quot;.$newArr['pid']); &lt;br /&gt;
     &lt;br /&gt;
      $name =   $objPaar-&amp;gt;partnernachname; &lt;br /&gt;
      if($objPaar-&amp;gt;partnervorname) &lt;br /&gt;
      { &lt;br /&gt;
        $name .= ', '.$objPaar-&amp;gt;partnervorname; &lt;br /&gt;
      } &lt;br /&gt;
      if($objPaar-&amp;gt;partnerinnachname) &lt;br /&gt;
      { &lt;br /&gt;
         $name .= ' und '.$objPaar-&amp;gt;partnerinnachname; &lt;br /&gt;
      } &lt;br /&gt;
      if($objPaar-&amp;gt;partnerinvorname) &lt;br /&gt;
      { &lt;br /&gt;
        $name .= ', '.$objPaar-&amp;gt;partnerinvorname; &lt;br /&gt;
      } &lt;br /&gt;
      $newArr['name'] = $name; &lt;br /&gt;
      $newArr['paaralias'] = $objPaar-&amp;gt;alias;  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und für jede Row aus der ''pid'' den Namen und den Alias des Turnierpaares bestimmen und mit ins assoziative Array aufnehmen.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      $arrMeldungen[] = $newArr; &lt;br /&gt;
    } &lt;br /&gt;
     &lt;br /&gt;
    $this-&amp;gt;Template-&amp;gt;meldungen = $arrMeldungen; &lt;br /&gt;
    } &lt;br /&gt;
} &lt;br /&gt;
?&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Schließlich wird jeder Datensatz an das große Ergebnisarray angehangen und dann ins Template geschrieben.&lt;br /&gt;
&lt;br /&gt;
Womit wir zu den Templates kommen. Zunächst ''/system/modules/gw_turnierpaare/templates/gw_meldeliste_error.tpl'' :&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;&amp;lt;?php echo $this-&amp;gt;class; ?&amp;gt; block meldeliste&amp;quot;&amp;lt;?php echo $this-&amp;gt;cssID; &lt;br /&gt;
?&amp;gt; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;style): ?&amp;gt; style=&amp;quot;&amp;lt;?php echo $this-&amp;gt;style; ?&amp;gt;&amp;quot;&amp;lt;?php endif; ?&amp;gt;&amp;gt; &lt;br /&gt;
&amp;lt;h3&amp;gt;Es trat ein Fehler auf!&amp;lt;/h3&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Erstmal easy as this, hier könnte man sich natürlich beliebig weiter austoben als nur mit diesem lapidaren Satz.&lt;br /&gt;
&lt;br /&gt;
Spannender ist ''/system/modules/gw_turnierpaare/templates/gw_meldeliste.tpl'':		&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;&amp;lt;?php echo $this-&amp;gt;class; ?&amp;gt;&amp;quot;&amp;lt;?php echo $this-&amp;gt;cssID; ?&amp;gt;&amp;lt;?php if &lt;br /&gt;
($this-&amp;gt;style): ?&amp;gt; style=&amp;quot;&amp;lt;?php echo $this-&amp;gt;style; ?&amp;gt;&amp;quot;&amp;lt;?php endif; ?&amp;gt;&amp;gt; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;headline): ?&amp;gt; &lt;br /&gt;
&amp;lt;&amp;lt;?php echo $this-&amp;gt;hl; ?&amp;gt;&amp;gt;&amp;lt;?php echo $this-&amp;gt;headline; ?&amp;gt;&amp;lt;/&amp;lt;?php echo $this-&amp;gt;hl; ?&lt;br /&gt;
&amp;gt;&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Standardauftakt...&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;table cellpadding=&amp;quot;4&amp;quot; cellspacing=&amp;quot;0&amp;quot; summary=&amp;quot;Meldeliste&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;thead&amp;gt; &lt;br /&gt;
    &amp;lt;tr&amp;gt; &lt;br /&gt;
      &amp;lt;th class=&amp;quot;centered&amp;quot;&amp;gt;Datum&amp;lt;/th&amp;gt;&lt;br /&gt;
      &amp;lt;th class=&amp;quot;centered&amp;quot;&amp;gt;Ort&amp;lt;/th&amp;gt; &lt;br /&gt;
      &amp;lt;th class=&amp;quot;centered&amp;quot;&amp;gt;Turnier&amp;lt;/th&amp;gt; &lt;br /&gt;
      &amp;lt;th class=&amp;quot;centered&amp;quot;&amp;gt;Turnierart&amp;lt;/th&amp;gt; &lt;br /&gt;
      &amp;lt;th class=&amp;quot;centered&amp;quot;&amp;gt;Platz&amp;lt;/th&amp;gt; &lt;br /&gt;
      &amp;lt;th class=&amp;quot;centered&amp;quot;&amp;gt;Paare&amp;lt;/th&amp;gt; &lt;br /&gt;
      &amp;lt;th class=&amp;quot;centered&amp;quot;&amp;gt;Bemerkung&amp;lt;/th&amp;gt; &lt;br /&gt;
    &amp;lt;/tr&amp;gt; &lt;br /&gt;
  &amp;lt;/thead&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
Header der Tabelle...&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;tbody&amp;gt; &lt;br /&gt;
&amp;lt;?php foreach ($this-&amp;gt;meldungen as $meldung): ?&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir gehen durch alle rows im Array durch.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;tr&amp;gt; &lt;br /&gt;
  &amp;lt;td class=&amp;quot;centered&amp;quot;&amp;gt; &lt;br /&gt;
  &amp;lt;?php echo date('d.m.Y', $meldung['datum']); ?&amp;gt; &lt;br /&gt;
  &amp;lt;/td&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Datum &amp;quot;richtig&amp;quot; formatieren...&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;a href=&amp;quot;&amp;lt;?php echo $this-&amp;gt;coupledetails; ?&amp;gt;&amp;lt;?php echo $meldung['paaralias']; ?&amp;gt;.html&amp;quot;&amp;gt;&amp;lt;?php echo $meldung['name']; ?&amp;gt;&amp;lt;/a&amp;gt; &lt;br /&gt;
  &amp;lt;/td&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier wird der Paarname und als hinterlegter Link die Detail-URL mit dem Paar-Alias ausgegeben.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;td class=&amp;quot;centered&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;?php echo $meldung['turnierort']; ?&amp;gt;&amp;lt;/strong&amp;gt; &lt;br /&gt;
  &amp;lt;/td&amp;gt; &lt;br /&gt;
  &amp;lt;td class=&amp;quot;centered&amp;lt;?php if ($meldung['lat_std'] == 'Std'){echo ' std';} else { &lt;br /&gt;
if ($meldung['lat_std'] == 'Lat'){echo ' lat';}}?&amp;gt;&amp;quot;&amp;gt;&amp;lt;?php echo $meldun&lt;br /&gt;
g['startgruppe']; ?&amp;gt; &amp;lt;?php echo $meldung['startklasse']; ?&amp;gt; &amp;lt;?php echo $meldun&lt;br /&gt;
g['lat_std']; ?&amp;gt; &lt;br /&gt;
  &amp;lt;/td&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
In Abhängigkeit von der Tanzart wird dem TD eine CSS-Klasse zugewiesen (zur farblichen Absetzung).&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;td class=&amp;quot;centered&amp;quot;&amp;gt;&amp;lt;?php echo $meldung['turnierart']; ?&amp;gt; &lt;br /&gt;
  &amp;lt;/td&amp;gt; &lt;br /&gt;
  &amp;lt;td class=&amp;quot;centered&amp;quot;&amp;gt;&amp;lt;?php echo $meldung['platz_von']; ?&amp;gt; &lt;br /&gt;
  &amp;lt;?php if (strlen($meldung['platz_bis']) &amp;gt; 0): ?&amp;gt; &lt;br /&gt;
  &amp;lt;?php if ($meldung['platz_von'] != $meldung['platz_bis']): ?&amp;gt; &lt;br /&gt;
  &amp;lt;?php echo &amp;quot; - &amp;quot;.$meldung['platz_bis']; ?&amp;gt; &lt;br /&gt;
  &amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
  &amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
  &amp;lt;/td&amp;gt; &lt;br /&gt;
  &amp;lt;td class=&amp;quot;centered&amp;quot;&amp;gt;&amp;lt;?php echo $meldung['anzahlpaare']; ?&amp;gt; &lt;br /&gt;
  &amp;lt;/td&amp;gt; &lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;?php echo $meldung['bemerkung']; ?&amp;gt; &lt;br /&gt;
  &amp;lt;/td&amp;gt; &lt;br /&gt;
  &amp;lt;/tr&amp;gt;&amp;lt;?php endforeach; ?&amp;gt; &lt;br /&gt;
  &amp;lt;/tbody&amp;gt; &lt;br /&gt;
&amp;lt;/table&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So weit unsere Tabelle...Es fehlen noch die Links, um eine Seite vor oder zurück zu springen...wenn es dann davor oder dahinter noch Seiten gibt.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;page &amp;gt; 1): ?&amp;gt; &lt;br /&gt;
&amp;lt;a id=&amp;quot;prev&amp;quot; href=&amp;quot;/{{env::page_alias}}/&amp;lt;?php echo gwMeldeliste::$strPageKey; ?&lt;br /&gt;
&amp;gt;/&amp;lt;?php echo ($this-&amp;gt;page-1); ?&amp;gt;.html&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;?php elseif ($this-&amp;gt;page == 1): ?&amp;gt; &lt;br /&gt;
&amp;lt;a href=&amp;quot;/{{env::page_alias}}.html&amp;quot;&amp;lt;&amp;lt;&amp;lt;&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;amp;nbsp;Seite &amp;lt;?php echo ($this-&amp;gt;page+1); ?&amp;gt;&amp;amp;nbsp; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;nextpage &amp;gt;= 0): ?&amp;gt; &lt;br /&gt;
&amp;lt;a id=&amp;quot;next&amp;quot; href=&amp;quot;/{{env::page_alias}}/&amp;lt;?php echo gwMeldeliste::$strPageKey; ?&lt;br /&gt;
&amp;gt;/&amp;lt;?php echo $this-&amp;gt;nextpage; ?&amp;gt;.html&amp;quot;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das liefert uns im Frontend (ohne weitere CSS-Modifikationen) bei 6 Meldungen (nur zur Demo) pro Seite: &lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_36.png]]&lt;br /&gt;
&lt;br /&gt;
und beim Weiterschalten auf die zweite Seite (.../page/1.html):&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_37.png]]&lt;br /&gt;
&lt;br /&gt;
Ein Klick auf den Turnierpaarnamen springt zur Detail-URL, bei mir /turnierpaarliste/info/&amp;lt;alias&amp;gt;.html:&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_38.png]]&lt;br /&gt;
&lt;br /&gt;
So, das soll es erstmal gewesen sein. Ich habe eine Menge gelernt, und würde den Code JETZT ganz anders aufziehen. Und das werde ich auch tun (haha). Allerdings ist der Zeithorizont unklar, und ich werde es auch nicht mehr schaffen &amp;quot;nebenbei&amp;quot; das Tagebuch zu führen. Pro Folge war es doch ca. eine Stunde Arbeit - mehr als gedacht! Mir fehlen für meinen Einsatz des Moduls auch noch einige kleine Features, aber das ist wirklich sehr speziell.&lt;br /&gt;
&lt;br /&gt;
Zunächst werde ich gemeinsam genutzte Funktionen der Back- und Frontendmodule wohl in eine gemeinsame Klasse packen, um die Module und auch die Templates etwas zu entschlacken.&lt;br /&gt;
&lt;br /&gt;
Vielleicht werde ich zu gegebener Zeit zum Thema &amp;quot;AJAX&amp;quot; in Frontendmodulen nochmal etwas schreiben, aber dann nur speziell auf diesen Teilbereich bezogen.&lt;br /&gt;
&lt;br /&gt;
Es tut mir leid, dass es hier die letzten Wochen etwas zäh und &amp;quot;langweilig&amp;quot; wurde, aber unerwarteter Weise war meine Freizeit (in der ich das hier tue) knapper als gedacht. Ich hoffe, Einige konnten teilweise Kleinigkeiten aus meinem Lernprozess mitnehmen , egal wie chaotisch er war, und für sich sinnvoll nutzen.&lt;br /&gt;
&lt;br /&gt;
==Diskussion aus dem Forum==&lt;br /&gt;
'''user: deerwood'''&lt;br /&gt;
 &lt;br /&gt;
Zum Schritt 13 habe ich noch 2 Anmerkungen:&lt;br /&gt;
&lt;br /&gt;
1. Statt Deinem Test für eine nächste Seite würde ich ein &amp;quot;SELECT COUNT(*) AS count FROM tl_gw_meldungen&amp;quot; machen, das kann MySQL sehr schnell, ohne wirklich auf die Datensätze zugreifen zu müssen. Basierend auf der Anzahl aller Datensätze und unter Berücksichtigung der Sätze pro Seite kann man dann eine beliebige Paginierung erzeugen (etwa auch &amp;quot;Erste/Letzte Seite&amp;quot; oder &amp;quot;5 Seiten weiter/zurück&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
2. Statt die Meldungen erst zu selektieren und dann in der WHILE Schleife die Paar-Infos (für die Namen) einzeln nachzuselektieren solltest Du vor der Schelife einen JOIN zwischen 'tl_gw_meldungen' und 'tl_gw_turnierpaare' machen und in der Schleife dann nur noch die Namen zusammensetzen. Das ist erheblich performanter, es wird nur 1 statt 51 Statements abgesetzt und JOIN ist ja nun gerade eine der Stärken von relationalen Datenbanken.&lt;br /&gt;
&lt;br /&gt;
Jedenfalls wünsche ich Dir sehr viel Erfolg bei Deiner geplanten Überarbeitung und ich würde mich SEHR freuen, wenn Du auch noch etwas zu AJAX schreibst.&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely'''&lt;br /&gt;
 &lt;br /&gt;
zu deerwood 1.   &lt;br /&gt;
Ja, das geht sicherlich auch, und mit der Gesamtzahl der Datensätze kann man die von dir beschriebenen Dinge umsetzen. Ob das bezüglich der Performance wirklich so viel Unterschied macht? Ich glaube nicht, dass das wirklich messbar ist, wenn es einmal Seitenabruf aufgerufen wird. Ich überlasse das mal als Übung dem interessierten Leser ;-).&lt;br /&gt;
&lt;br /&gt;
zu deerwood 2.  &lt;br /&gt;
Ja, da hast Du natürlich völlig recht. Ein Join ist deutlich besser. So wie ich das gemacht habe, war das quick'n'dirty, und sollte nicht als Vorbild dienen. Mir war erstmal unklar, welche Keys im assoziativen Array genutzt werden, wenn ich zwei Tabellen joine. Muss ich ein Feld wie &amp;quot;tabelle2.partnernachname&amp;quot; dann immer mit &amp;quot;AS&amp;quot; umbenennen? Ich muss mir mal anschauen, wie das in anderen Modulen gemacht wird, und dann schiebe ich nochmal eine Version nach, die es besser macht, und die Anzahl der Queries in der Tat drastisch reduziert :-).&lt;br /&gt;
&lt;br /&gt;
=JOIN-Power=&lt;br /&gt;
Wie oben besprochen habe ich die Schleife über die Meldungen durch einen Join ersetzt. Im assoziativen Array werden einfach die Feldnamen aus jeder Tabelle benutzt, bei Konflikten gewinnt vermutlich die letztgenannte Tabelle(?).&lt;br /&gt;
&lt;br /&gt;
''/system/modules/gw_turnierpaare/gwMeldeliste.php'' sieht jetzt im unteren Teil so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $objMeldungen = $this-&amp;gt;Database-&amp;gt;execute(&amp;quot;SELECT * FROM tl_gw_meldungen m, tl_&lt;br /&gt;
gw_turnierpaare p WHERE m.pid = p.id ORDER BY datum DESC&amp;quot;.$limit); &lt;br /&gt;
     &lt;br /&gt;
    if($objMeldungen-&amp;gt;numRows == 0) &lt;br /&gt;
    { &lt;br /&gt;
      // Error &lt;br /&gt;
      $this-&amp;gt;Template = new FrontendTemplate($this-&amp;gt;strErrorTemplate); &lt;br /&gt;
      return;&lt;br /&gt;
    } &lt;br /&gt;
       &lt;br /&gt;
    $arrMeldungen = $objMeldungen-&amp;gt;fetchAllAssoc(); &lt;br /&gt;
    $templateResult = array(); &lt;br /&gt;
    foreach($arrMeldungen as $meldung) &lt;br /&gt;
    { &lt;br /&gt;
      $name = $meldung['partnernachname']; &lt;br /&gt;
      if($meldung['partnervorname']) &lt;br /&gt;
      { &lt;br /&gt;
        $name .= ', '.$meldung['partnervorname']; &lt;br /&gt;
      } &lt;br /&gt;
      if($meldung['partnerinnachname']) &lt;br /&gt;
      { &lt;br /&gt;
        $name .= ' und '.$meldung['partnerinnachname']; &lt;br /&gt;
      } &lt;br /&gt;
      if($meldung['partnerinvorname']) &lt;br /&gt;
      { &lt;br /&gt;
        $name .= ', '.$meldung['partnerinvorname']; &lt;br /&gt;
      } &lt;br /&gt;
      $meldung['name'] = $name; &lt;br /&gt;
      $templateResult[] = $meldung; &lt;br /&gt;
    } &lt;br /&gt;
    $this-&amp;gt;Template-&amp;gt;meldungen = $templateResult; &lt;br /&gt;
    } &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also statt einer Schleife über alle Rows mit neuem SELECT für den Paarnamen nurnoch eine Schleife über alle Result-Rows, um aus den Namensbestandteilen den Anzeigenamen zu basteln...Wesentlich performanter!&lt;br /&gt;
&lt;br /&gt;
==Diskussion aus dem Forum==&lt;br /&gt;
'''user: MBM''' &lt;br /&gt;
&lt;br /&gt;
Detailseiten &lt;br /&gt;
ich habe mir Dein Modul mal runtergeladen und es mal installiert und getestet. Es funktioniert auch soweit bis auf die Ansicht der Detailseite. Bekomme immer ein Page not found...&lt;br /&gt;
&lt;br /&gt;
Ich frage mich wie Du das gelöst hast. Hat es vielleicht mit meiner Konfiguration des Apache Webserver zu tun? Ich benutze in der Apache Konfiguration mod_rewrite und das Contao CMS 2.8.3 liegt in einem ALIAS Ordner. Auch ist inder CMS Konfiguration die index.php Anzeige ausgeschaltet (eben mod_rewrite).&lt;br /&gt;
URL: http://webserver/contao/&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;alias &amp;quot;/&amp;lt;pfad&amp;gt;/contao_tuts&amp;quot;&amp;gt;&lt;br /&gt;
RewriteBase /contao&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
Da wird bestimmt der Hund im Thema &amp;quot;Wie baue ich die Detail-URL zusammen&amp;quot; begraben sein. Wie sieht denn die &amp;quot;normale&amp;quot; URL der Meldeliste aus, und welche URL wird versucht aufzurufen, wenn Du den &amp;quot;Detail&amp;quot;-Link anklickst? Kannst den Domainnamen ja gerne weglassen.&lt;br /&gt;
&lt;br /&gt;
Es kann gut sein, dass mein Ansatz für die Detail-URL nur bei bestimmten Randbedingungen funktioniert, dann müsste ich das nochmal nachbessern.&lt;br /&gt;
&lt;br /&gt;
'''user: MBM''' &lt;br /&gt;
Hooks &lt;br /&gt;
 Zitat von dl1ely   &lt;br /&gt;
Hallo!&lt;br /&gt;
Da wird bestimmt der Hund im Thema &amp;quot;Wie baue ich die Detail-URL zusammen&amp;quot; begraben sein.&lt;br /&gt;
Hunde begraben   ? Mich würde ja interessieren unter welcher Konfiguration das bei Dir läuft.&lt;br /&gt;
Nun ja, ich habe jetzt auch eine Lösung entwickelt. Ich weiß zwar auch nicht ob das Best Practise ist und ob es &lt;br /&gt;
nicht einen einfacheren Weg gibt, aber es funktioniert.&lt;br /&gt;
&lt;br /&gt;
 Zitat von dl1ely   &lt;br /&gt;
Wie sieht denn die &amp;quot;normale&amp;quot; URL der Meldeliste aus, und welche URL wird versucht aufzurufen, wenn Du den  &lt;br /&gt;
&amp;quot;Detail&amp;quot;-Link anklickst? Kannst den Domainnamen ja gerne weglassen.&lt;br /&gt;
Meine Konfigurationsparameter&lt;br /&gt;
Im Backend ist URL's umschreiben auf aktiv gestellt.&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Hauptlink: http://cms/contao/turnierpaareliste.html&lt;br /&gt;
Detaillink: http://cms/contao/turnierpaareliste/info/test_testin.htm&lt;br /&gt;
# htaccess&lt;br /&gt;
RewriteBase /contao&lt;br /&gt;
RewriteRule ^(.*)/info/(.*)$ $1.html?info=$2&lt;br /&gt;
RewriteRule .*\.html$ index.php [L]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Zitat von dl1ely   &lt;br /&gt;
Es kann gut sein, dass mein Ansatz für die Detail-URL nur bei bestimmten Randbedingungen funktioniert, dann müsste ich das nochmal nachbessern.&lt;br /&gt;
&lt;br /&gt;
Ich habe nun ein wenig experimentiert und zwei Lösungen gefunden. &lt;br /&gt;
Die erste war Quick &amp;amp; Dirty und ist nicht update sicher und die zweite könnte gehen.&lt;br /&gt;
&lt;br /&gt;
Lösung 1: index.php ergänzen (Nicht zu empfehlen)&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function run() &lt;br /&gt;
    { &lt;br /&gt;
        global $objPage; &lt;br /&gt;
        // Get page ID &lt;br /&gt;
        $pageId = $this-&amp;gt;getPageIdFromUrl(); &lt;br /&gt;
                // filter  alias &lt;br /&gt;
        if (stripos($pageId, '/info') &amp;gt;0 ) &lt;br /&gt;
        { &lt;br /&gt;
            $pageId = substr($pageId,0,stripos($pageId, '/info')); &lt;br /&gt;
        } &lt;br /&gt;
}  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lösung 2: Hook &lt;br /&gt;
&lt;br /&gt;
2.1 Ergänzung des TL-Hook array.&lt;br /&gt;
&lt;br /&gt;
''config.php'' - ''/system/modules/gw_turnierpaare/config/''&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$GLOBALS['TL_HOOKS']['getPageIdFromUrl'][] = array('gwHook', 'gwGetPageIdFromUrl'); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
2.2 Hook Klassendatei erstellen.&lt;br /&gt;
&lt;br /&gt;
''gwHook.php'' - ''/system/modules/gw_turnierpaare/''&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class gwHook extends Controller &lt;br /&gt;
{ &lt;br /&gt;
 public function  gwGetPageIdFromUrl($arrFragments) &lt;br /&gt;
 { &lt;br /&gt;
    // get alias (-url)     &lt;br /&gt;
     $url = explode('/', $arrFragments[0]) ; &lt;br /&gt;
    // filter or cut, seo parameter and set only alias &lt;br /&gt;
     $arrFragments[0] = $url[0] ; &lt;br /&gt;
       return array_unique($arrFragments);  &lt;br /&gt;
}       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
Hallo MBM,&lt;br /&gt;
sorry für die verspätete Antwort, aber ich war leider ziemlich beschäftigt. Ich kann dir auf Anhieb nicht sagen, warum das nicht so funktioniert wie bei mir.&lt;br /&gt;
&lt;br /&gt;
In meiner .htaccess ist &amp;quot;RewriteBase /&amp;quot;, da die Contao-Installation nicht in einem Unterverzeichnis liegt. Sonst habe ich auch &amp;quot;nur&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RewriteRule .*\.html$ index.php [L]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in der .htaccess .&lt;br /&gt;
&lt;br /&gt;
Bei der Detail-URL schreibst du nur was von &amp;quot;.htm&amp;quot; am Ende der URL. Das ist aber sicherlich auch &amp;quot;.html&amp;quot;, genau wie bei der Übersichts-URL, oder?&lt;br /&gt;
&lt;br /&gt;
Bis auf die Rewritebase sehe ich erstmal keinen zwingenden Unterschied. Aber es wundert mich, dass es daran haken soll.&lt;br /&gt;
&lt;br /&gt;
Dass du schon eine Menge gelernt hast zeigt ja dein Lösungsansatz mit dem Hook, das zeugt vom Lernerfolg ;-).&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-12_Backend_Callback-Magie</id>
		<title>TEE-12 Backend Callback-Magie</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-12_Backend_Callback-Magie"/>
				<updated>2010-07-07T21:23:15Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Callback-Magie=&lt;br /&gt;
Ja, nach langer Pause geht es wirklich weiter. Diesmal wird die Backendpflege der &amp;quot;Meldungen&amp;quot;-Tabelle komplettiert. Gegenüber dem letzten Schritt haben sich nach fruchtbarer Diskussion einige Änderungen ergeben.&lt;br /&gt;
&lt;br /&gt;
Zunächst die Datenbankdefinition der Tabelle ''tl_gw_meldungen'' in ''system/modules/tl_gw_turnierpaare/config/database.sql'':&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-- &lt;br /&gt;
-- Table `tl_gw_meldungen`&lt;br /&gt;
-- &lt;br /&gt;
CREATE TABLE `tl_gw_meldungen` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `pid` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `datum` varchar(10) NOT NULL default '',&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '',&lt;br /&gt;
  `startklasse` varchar(12) NOT NULL default '',&lt;br /&gt;
  `lat_std` char(32) NOT NULL default '',&lt;br /&gt;
  `turnierort` varchar(128) NOT NULL default '',&lt;br /&gt;
  `turnierart` varchar(64) NULL default NULL,&lt;br /&gt;
  `anzahlpaare` int(4) NULL default NULL,&lt;br /&gt;
  `platz_von` int(4) NULL default NULL,&lt;br /&gt;
  `platz_bis` int(4) NULL default NULL,&lt;br /&gt;
  `bemerkung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
  KEY `pid` (`pid`)&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Feld datum war vorher vom Typ ''date'', aber das funktioniert so nicht, wenn man es als Datumsfeld im Backend verwenden will. Darum jetzt ein ''varchar(10)''. Der Rest blieb unverändert.&lt;br /&gt;
&lt;br /&gt;
Auch das Einfügen der Backendmodule in die Auswahlleiste auf der linken Seite des Backends ändere ich in ''/system/modules/tl_gw_turnierpaare/config/config.php'' ab:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Back end module &lt;br /&gt;
array_insert($GLOBALS['BE_MOD'], 0, array( &lt;br /&gt;
    'gw_paarverwaltung' =&amp;gt; array( &lt;br /&gt;
      'gw_turnierpaare' =&amp;gt; array &lt;br /&gt;
      ( &lt;br /&gt;
        'tables' =&amp;gt; array('tl_gw_turnierpaare'), &lt;br /&gt;
        'icon'   =&amp;gt; 'system/modules/gw_turnierpaare/icons/turnierpaare.png' &lt;br /&gt;
      ), &lt;br /&gt;
      'gw_meldungen' =&amp;gt; array &lt;br /&gt;
      ( &lt;br /&gt;
        'tables' =&amp;gt; array('tl_gw_meldungen'), &lt;br /&gt;
        'icon'   =&amp;gt; 'system/modules/gw_turnierpaare/icons/meldeliste.png' &lt;br /&gt;
      ) &lt;br /&gt;
    ) &lt;br /&gt;
  ) &lt;br /&gt;
);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Durch das ''array_insert'' kann ich mit zweiten Parameter steuern, an welcher Stelle das als letzter Parameter angegebene Array eingefügt werden soll. Bei einer &amp;quot;0&amp;quot; wie hier wandern meine Arrayeinträge ganz nach oben,bei einer &amp;quot;1&amp;quot; an zweite Stelle, usw. Da in der Praxis auf der Webseite häufiger neue Turnierpaarmeldungen eingegeben werden als neue Artikel, mächte ich die Turnierpaarverwaltung gerne ganz oben haben.&lt;br /&gt;
&lt;br /&gt;
Und dadurch, dass ich in dem Array was ich einfüge eine zusätzliche Ebene ''gw_paarverwaltung'' habe, gruppiere ich die beiden Einträge ''gw_turnierpaare'' und ''gw_meldungen'' in eine Untergruppe innerhalb des Menüs. Das schafft mehr Übersicht.&lt;br /&gt;
&lt;br /&gt;
Um die Language-Datei für diese Einträge muss ich mich jetzt auch einmal kümmern (''/system/modules/tl_gw_turnierpaare/languages/modules.php''):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Back end modules &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['gw_turnierpaare'] = array('Turnierpaare', 'Verwaltung der Turnierpaare.'); &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['gw_meldungen'] = array('Meldungen', 'Verwaltung der Turniermeldungen (Meldeliste).'); &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['gw_paarverwaltung'] = 'Paarverwaltung';  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''ACHTUNG''': Während die Language-Einträge für die Module selbst ein Array bestehend aus dem Label des Menüeintrags und dem Beschreibungstext des Moduls sein müssen, ist der Label für die Überschrift der Gruppe im Menü (''gw_paarverwaltung'') nur ein einfacher String!&lt;br /&gt;
&lt;br /&gt;
Wie sieht das nun aus?&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_31.png]]&lt;br /&gt;
&lt;br /&gt;
Wo wir schonmal bei den Language-Dateien sind, machen wir auch noch die Label für die Felder des Backendmoduls  (''/system/modules/tl_gw_turnierpaare/languages/de/tl_gw_meldungen.php''):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php if (!defined('TL_ROOT')) die('You can not access this file directly!'); &lt;br /&gt;
/** &lt;br /&gt;
 * Fields &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['pid'] = array('Paar', 'Turnierpaar auswählen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['datum'] = array('Turnierdatum', 'Turnierdatum eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierort'] = array('Turnierort', 'Turnierort eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierart'] = array('Turnierform', 'Turnierform auswählen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['startgruppe'] = array('Startgruppe', 'Startgruppe auswählen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['startklasse'] = array('Startklasse', 'Startklasse auswählen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['lat_std'] = array('Latein/Standard', 'Tanzart auswählen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['anzahlpaare'] = array('Anzahl gestarteter Paare', 'Die Paaranzahl des Turniers eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_von'] = array('Platz', 'Erzielter Platz'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_bis'] = array('Platz bis', 'Geteilter Platz: Platz bis... - sonst leer lassen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['bemerkung'] = array('Bemerkung', 'Bemerkung eingeben'); &lt;br /&gt;
/** &lt;br /&gt;
 * Reference &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['couple_legend'] = 'Paar'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['tournament_legend'] = 'Turnier'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['result_legend'] = 'Ergebnis'; &lt;br /&gt;
/** &lt;br /&gt;
 * Buttons &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['new']    = array('Neue Meldung', 'Eine neue Turniermeldung anlegen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['edit']   = array('Editieren', 'Die Turniermeldung editieren'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['copy']   = array('Meldung kopieren', 'Die Turniermeldung in die Zwischenablage kopieren'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['delete'] = array('Meldung löschen', 'Die Turniermeldung aus der Liste entfernen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['show']   = array('Details', 'Die Detailansicht der Turniermeldung anzeigen'); &lt;br /&gt;
?&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da muss ich wohl nicht mehr viel zu schreiben: Der erste Block sind Label und Beschreibungen für die Eingabefelder, der zweite Block sind die Label für die Palettenüberschriften, und die dritte Gruppe schließlich die Label und Beschreibungen für die &amp;quot;Aktionsbuttons&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Kommen wir zum spannenden Teil, mit dem ich im [[TEE-11_Backend_Zweite_Tabelle|Schritt 11]] ja noch einen Kampf zu fechten hatte: der DCA-Record  (''/system/modules/tl_gw_turnierpaare/dca/tl_gw_meldungen.php''):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php if (!defined('TL_ROOT')) die('You can not access this file directly!'); &lt;br /&gt;
/** &lt;br /&gt;
 * Table tl_gw_meldungen  &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_DCA']['tl_gw_meldungen'] = array &lt;br /&gt;
( &lt;br /&gt;
    // Config &lt;br /&gt;
    'config' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'dataContainer'               =&amp;gt; 'Table', &lt;br /&gt;
        'enableVersioning'            =&amp;gt; true, &lt;br /&gt;
    ), &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier so weit nichts Spannendes: Weiterhin wird eine Tabelle bearbeitet, und ich aktiviere Versionierung.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // List &lt;br /&gt;
    'list' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'sorting' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'mode'                    =&amp;gt; 2, &lt;br /&gt;
            'fields'                  =&amp;gt; array('datum DESC', 'turnierort', 'pid'), &lt;br /&gt;
            'panelLayout'             =&amp;gt; 'filter;sort,search,limit' &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mode = 2 bedeutet, dass das Sortierfeld im Header der Tabelle wählbar ist, defaultmäßig sortiere ich nach Turnierdatum (Jüngste ganz oben), dann dem Ort, und schließlich der Paar-ID.&lt;br /&gt;
&lt;br /&gt;
Mit ''panelLayout'' aktiviere ich die Paletten oben am Kopf der Tabelle, um das Sortierfeld wählbar zu machen, das Suchfeld zu aktivieren und die Anzahl der Treffer limitieren zu können.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'label' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'fields'                  =&amp;gt; array('datum','turnierort', 'turnierart', 'startgruppe','startklasse','lat_std'), &lt;br /&gt;
            'format'                  =&amp;gt; '%s - #name# - &amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt; - &amp;lt;span style=&amp;quot;color: #section_colour#;&amp;quot;&amp;gt;%s %s %s %s&amp;lt;/span&amp;gt;', &lt;br /&gt;
            'label_callback'          =&amp;gt; array('tl_gw_meldungen', 'lookup_pid') &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So, hier beginnt etwas die Magie...ich bastele mir das Format der Ausgabezeilen für die Backendansicht.&lt;br /&gt;
 &lt;br /&gt;
Leider habe ich hier nur die Felder der aktuellen Tabelle (''tl_gw_meldungen'') zur Verfügung, ich möchte aber gerne den Namen des Paares anzeigen, was zur ''pid'' gehört, die im Datensatz steht (''pid'' ist der Foreign Key in die ''tl_gw_turnierpaare''-Tabelle. Im klassischen SQL würde ich hier also einen JOIN machen). &lt;br /&gt;
&lt;br /&gt;
So direkt geht das leider nicht, darum definiere ich einen ''label_callback'', der weiter unten in dieser Datei als Funktion ''lookup_pid()'' in der Klasse ''tl_gw_meldungen'' definiert wird. Die Felder, die ich jetzt schon habe, definiere ich auch direkt im String. Für den Namen des Paares setze ich zunächst einen Platzhalter &amp;quot;#name#&amp;quot; in den String. &lt;br /&gt;
&lt;br /&gt;
Außerdem gibt es noch einen Platzhalter &amp;quot;#section_colour#&amp;quot;. Ich möchte Turnierstarts in der Tanzform Standardtänze in orange darstellen, und solche in der Tanzform Lateinamerikanische Tänze in rot. Das kann ich an dieser Stelle im DCA-Record nicht entscheiden, weil es vom Inhalt des Felds ''lat_std'' abhängt. Auch das wird im ''label_callback'' geregelt.&lt;br /&gt;
&lt;br /&gt;
Die Platzhalter werden im ''label_callback'' durch ein ''str_replace'' mit den gewünschten Werten ersetzt. Schön ist das nicht, aber funktioniert.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'global_operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'all' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['MSC']['all'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=select', &lt;br /&gt;
                'class'               =&amp;gt; 'header_edit_all', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ) &lt;br /&gt;
        ), &lt;br /&gt;
        'operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'edit' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['edit'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=edit', &lt;br /&gt;
                'icon'                =&amp;gt; 'edit.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'copy' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['copy'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=copy', &lt;br /&gt;
                'icon'                =&amp;gt; 'copy.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'delete' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['delete'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=delete', &lt;br /&gt;
                'icon'                =&amp;gt; 'delete.gif', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;if (!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\')) return false; Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ), &lt;br /&gt;
            'show' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['show'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=show', &lt;br /&gt;
                'icon'                =&amp;gt; 'show.gif' &lt;br /&gt;
            ) &lt;br /&gt;
        ) &lt;br /&gt;
    ),  					 &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu den globalen Operationen gibt es eigentlich nichts zu sagen. Die bleiben so, wie der ''Extension-Creator'' sie angelegt hat...&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '{couple_legend},pid;&lt;br /&gt;
{tournament_legend},datum,turnierort,turnierart,startgruppe,startklas&lt;br /&gt;
                                    .'{result_legend},anzahlpaare,plabis,bemerkung;' &lt;br /&gt;
    ), &lt;br /&gt;
    // Subpalettes &lt;br /&gt;
    'subpalettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        ''                            =&amp;gt; '' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;	 &lt;br /&gt;
	 &lt;br /&gt;
Die Palettendefinition hat sich nicht geändert, und Subpaletten gibt es weiterhin nicht.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'pid' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['pid'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'options_callback'        =&amp;gt; array('tl_gw_meldungen', 'getActiveCouples'), &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true) &lt;br /&gt;
        ), &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
		  &lt;br /&gt;
Das Feld ''pid'' war bisher ein ''foreignKey''-Feld, aber damit konnte ich z.B. nur mit dem Partner-Nachnamen verknüpfen, nicht mit dem Paarnamen. Außerdem wurden hier immer ALLE Paare angezeigt, hier sollen aber nur AKTIVE Paare auswählbar sein. Um das besser machen zu können, definiere ich die Möglichkeiten in der Dropdown-Box selbst durch den ''options_callback'' ''getActiveCouples()'' in der Klasse ''tl_gw_meldungen'', die gleich noch folgt.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'datum' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['datum'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 6,&lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'datepicker'=&amp;gt;$this-&amp;gt;getDatePickerString(), 'tl_class'=&amp;gt;'w50 wizard', 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;10, 'rgxp' =&amp;gt; 'date') &lt;br /&gt;
        ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
		  &lt;br /&gt;
''flag =&amp;gt; 6'' ist hier der große Trick, damit das Timestamp-Format von &amp;quot;datum&amp;quot; richtig als Datum im Format TT.MM.JJJJ angezeigt wird. Abgeguckt habe ich das übrigens im Backend in ''/system/modules/backend/dca/tl_log.php''.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'turnierort' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierort'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 11, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;128, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'turnierart' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierart'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 11, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$TurnierArten, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'startgruppe' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['startgruppe'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 11, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$StartGruppen, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'includeBlankOption' =&amp;gt; true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'startklasse' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['startklasse'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 11, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$StartKlassen, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'lat_std' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['lat_std'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'sorting'                 =&amp;gt; false, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$TanzArten, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'anzahlpaare' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['anzahlpaare'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;4, 'rgxp' =&amp;gt; 'digit') &lt;br /&gt;
        ), &lt;br /&gt;
        'platz_von' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_von'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;4, 'rgxp' =&amp;gt; 'digit', 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'platz_bis' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_bis'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;4, 'rgxp' =&amp;gt; 'digit', 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'bemerkung' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['bemerkung'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'textarea', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'cols' =&amp;gt; 80, 'rows' =&amp;gt; 20, 'allowHtml' =&amp;gt; false) &lt;br /&gt;
        ), &lt;br /&gt;
    ) &lt;br /&gt;
);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier gibt es keine großen Besonderheiten mehr. Gegenüber [[TEE-11_Backend_Zweite_Tabelle|Schritt 11]] habe ich die durchsuchbaren und sortierbaren Felder etwas erweitert bzw. geändert.&lt;br /&gt;
&lt;br /&gt;
Nun kommt die Backendklasse, in der ich die Callbacks unterbringe:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class tl_gw_meldungen extends Backend &lt;br /&gt;
{ &lt;br /&gt;
    /** &lt;br /&gt;
     * Import the back end user object &lt;br /&gt;
     */ &lt;br /&gt;
    public function __construct() &lt;br /&gt;
    { &lt;br /&gt;
        parent::__construct(); &lt;br /&gt;
        $this-&amp;gt;import('BackendUser', 'User'); &lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
	 &lt;br /&gt;
Auftaktgeplänkel...&lt;br /&gt;
&lt;br /&gt;
Zunächst der ''options_callback'', der mir die Liste der aktiven Turnierpaare für die Auswahl in der Dropdown-Box liefert:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  public function getActiveCouples() &lt;br /&gt;
  { &lt;br /&gt;
      $couples = array(); &lt;br /&gt;
        // Get all the active couples 		  &lt;br /&gt;
        $objCouples = $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;SELECT id,partnernachname,partnervorname,partnerinnachname,partnerinvorname FROM tl_gw_turnierpaare WHERE aktiv='1' &lt;br /&gt;
ORDER by partnernachname, partnervorname, partnerinnachname, partnerinvorname&amp;quot;) &lt;br /&gt;
                            -&amp;gt;execute(); &lt;br /&gt;
        while ($objCouples-&amp;gt;next()) &lt;br /&gt;
        { &lt;br /&gt;
            $k = $objCouples-&amp;gt;id; &lt;br /&gt;
            $v = $objCouples-&amp;gt;partnernachname; &lt;br /&gt;
            if($objCouples-&amp;gt;partnervorname) &lt;br /&gt;
            { &lt;br /&gt;
               $v .= ', '.$objCouples-&amp;gt;partnervorname; &lt;br /&gt;
      } &lt;br /&gt;
      if($objCouples-&amp;gt;partnerinnachname) &lt;br /&gt;
      { &lt;br /&gt;
        $v .= ' und '.$objCouples-&amp;gt;partnerinnachname; &lt;br /&gt;
        if($objCouples-&amp;gt;partnerinvorname) &lt;br /&gt;
              { &lt;br /&gt;
                 $v .= ', '.$objCouples-&amp;gt;partnerinvorname; &lt;br /&gt;
        } &lt;br /&gt;
      } &lt;br /&gt;
            $couples[$k] =$v; &lt;br /&gt;
        } &lt;br /&gt;
        return $couples; &lt;br /&gt;
  } &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
Der größte Teil der Funktion ist eigentlich das &amp;quot;Zusammenbasteln&amp;quot; des Paarnamens aus den Einzelbestandteilen der Namen von Partner und Partnerin. Zunächst werden aus der ''tl_gw_turnierpaare''-Tabelle die Namen der aktiven Paare selektiert und der Ergebnisstring daraus zusammengesetzt. Das Ergebnis wird dann einem Array zugewiesen, wobei die ID des Paares der Array-Key ist, und der Paarname der Value - also z.B. $couples[47] = &amp;quot;Wupp, Willi und Wupp, Sieglinde&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In der Dropdownbox steht der String, und wenn ich den dort auswähle, landet die ID 47 als ''pid'' in der Datenbanktabelle ''tl_gw_meldungen''. Und, was noch vieeeeel cooler ist: Wenn ich nach dem ''pid''-Feld sortiere, dann werden auch die Sortierheader durch die entsprechenden Strings ersetzt, statt dass dort der numerische ''pid''-Wert steht. Leider erfolgt die Sortierung natürlich nach dem Key, nicht nach dem Value...aber das wäre ja fast zuviel verlangt :-).&lt;br /&gt;
&lt;br /&gt;
Weiter geht es mit ''label_callback''. Als erstes Argument bekommt der die aktuelle Zeile aus der Datenbank, als zweites Argument den Label, wie er weiter oben im DCA-Record definiert wurde, hier also mit dem Platzhaltern #name# und #section_colour#.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:	&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function lookup_pid($row, $label) &lt;br /&gt;
    { &lt;br /&gt;
        $pid = $row['pid']; &lt;br /&gt;
         &lt;br /&gt;
        // Datensatz mit ID pid aus Tabelle tl_gw_turnierpaare holen &lt;br /&gt;
    $prow = $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;SELECT * FROM tl_gw_turnierpaare WHERE id=?&amp;quot;) &lt;br /&gt;
                              -&amp;gt;execute($pid);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit der pid aus dem aktuellen Datensatz holen wir den Datensatz des Turnierpaares...&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $name = '&amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;'.$prow-&amp;gt;partnernachname.'&amp;lt;/span&amp;gt;'; &lt;br /&gt;
    if($prow-&amp;gt;partnervorname) &lt;br /&gt;
    { &lt;br /&gt;
      $name .= ', '.$prow-&amp;gt;partnervorname; &lt;br /&gt;
    }; &lt;br /&gt;
    if($prow-&amp;gt;partnerinnachname) &lt;br /&gt;
    { &lt;br /&gt;
      $name .= ' und &amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;'.$prow-&amp;gt;partnerinnachname.'&amp;lt;/span&amp;gt;'; &lt;br /&gt;
      if($prow-&amp;gt;partnerinvorname) &lt;br /&gt;
      { &lt;br /&gt;
        $name .= ', '.$prow-&amp;gt;partnerinvorname; &lt;br /&gt;
      } &lt;br /&gt;
    };  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...und bauen aus den Namensbestandteilen den Paarnamen zusammen, wobei die Nachnamen fett erscheinen sollen.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $colour = 'black'; &lt;br /&gt;
    switch($row['lat_std']) &lt;br /&gt;
    { &lt;br /&gt;
      case 'Std': &lt;br /&gt;
        $colour = 'orange'; &lt;br /&gt;
        break; &lt;br /&gt;
      case 'Lat': &lt;br /&gt;
        $colour = 'red'; &lt;br /&gt;
        break; &lt;br /&gt;
    }  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Abhängigkeit vom Inhalt des ''lat_std''-Feldes wird eine Farbe zugewiesen. Falls der Inhalt unbekannt ist, bleibt die Schrift schwarz.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $label = str_replace('#section_colour#', $colour, $label); &lt;br /&gt;
     &lt;br /&gt;
    $label = str_replace('#name#', $name, $label); &lt;br /&gt;
     &lt;br /&gt;
    return $label; &lt;br /&gt;
  } &lt;br /&gt;
};   &lt;br /&gt;
?&amp;gt;  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir ersetzen die Platzhalter #name# und #section_colour# im Label-String durch die neu berechneten Werte, und geben den Label zurück.&lt;br /&gt;
&lt;br /&gt;
Was haben wir damit nun erreicht:&lt;br /&gt;
				&lt;br /&gt;
[[Datei:gw_turnierpaare_32.png]]&lt;br /&gt;
&lt;br /&gt;
Unsere Startmeldungen sind nach dem Datum sortiert, die Nachnamen im Paarnamen sind fett, die Stadt auch, und die &amp;quot;Kategorisierung&amp;quot; des Turniers ist orange oder rot, je nachdem ob es um Standardtänze oder lateinamerikanische Tänze geht.&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_33.png]]&lt;br /&gt;
&lt;br /&gt;
Sortieren wir nach den Paaren, dann wird die numerische pid in den Sortierheader durch unseren options_callback in die entsprechenden Strings umgesetzt - sehr nett. Leider erfolgt die Sortierung weiterhin numerisch nach der pid, und nicht alphabetisch nach den Strings. Vielleicht hat jemand noch eine Idee, wie man das lösen könnte?&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_34.png]]&lt;br /&gt;
&lt;br /&gt;
Und bei Neuanlage einer Turniermeldung werden in der Dropdown-Liste nurnoch die aktiven Paare aufgeführt, nicht mehr ALLE.&lt;br /&gt;
&lt;br /&gt;
Im nächsten Schritt geht es ans Frontendmodul für die Meldeliste... &lt;br /&gt;
&lt;br /&gt;
Ich bin gerade in der DCA-Referenz über das Feld ''findInSet'' unter ''eval'' gestolpert: &amp;quot;Sort by the actual option values instead of their labels (available from version 2.7.RC1).&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Das klingt wie das, was ich gerne für mein ''pid''-Feld hätte, d.h. Sortierung nach den Paarnamen, die sich aus der ''pid'' ergeben anstatt numerisch nach dem ''pid''-Wert. Leider wirft das einen Fehler in ''DC_Table.php'' (Zeile 3468 bei TL 2.8.3), wo ''$keys'' nicht definiert ist. Wenn ich das richtig sehe, funktioniert das nämlich nur mit hardcodierten &amp;quot;options&amp;quot; im DCA-Record (Zeile 3461), ein ''options_callback'' wird dort nicht ausgewertet.&lt;br /&gt;
&lt;br /&gt;
Kann das einer der &amp;quot;Profis&amp;quot; bestätigen? Wäre das dann nicht evtl. ein kleiner lohnenswerter Punkt für einen Feature-Request? Sieht für mich nach einem Zweizeiler der Marke &amp;quot;Falls options nicht gesetzt ist options_callback ausführen, dann weitermachen&amp;quot; aus.&lt;br /&gt;
&lt;br /&gt;
'''EDIT''': Ich habe mal ein Ticket dafür gemacht: http://dev.typolight.org/issues/1914&lt;br /&gt;
Habe meine ''DC_Table.php'' entsprechend angepasst, und damit funktioniert es bei mir wie gewünscht.&lt;br /&gt;
&lt;br /&gt;
==Diskussion aus dem Forum==&lt;br /&gt;
{{Hinweis|Die Wiedergabe folgt dem Forums-Thread, der verschiedene Thematiken aufwirft. Sie muss daher noch umgearbeitet werden.}}&lt;br /&gt;
&lt;br /&gt;
'''user: Setsunaa'''&lt;br /&gt;
&lt;br /&gt;
Ich Entwickel seit zwei Monaten an einem Webseiten Katalog und wusste echt nicht was da auf mich zu kommt. Leider sind solche Art von &amp;quot;Katalogen&amp;quot; eher weniger vertreten und auch die catalouge extension für meine Dienste doch etwas zu überladen ist(da ich nix verkaufe) musste ich mich mit den gleichen Sachen asueinandersetzen und dein Tagebuch war eine große hilfe.&lt;br /&gt;
&lt;br /&gt;
auch wenn ich oft geflucht ahbe, denn bei dir funktionierten Sachen, die ich etwas umständlciher machen musste. Was aber auch an meiner Datenbank struktur liegt. Hällt man sich nicht an die gedachten Strukturen, muss man einiges nachimplementieren. Um genauer zu sein ist es für mein vorhaben nicht so simpel nur 1:n beziheungen zu finden. &lt;br /&gt;
&lt;br /&gt;
Zum Verständniss: eine Webseite hat einen ersteller/empfehler und einen Webmaster/Kontaktperson. Diese können gleich aber auch unterschiedlcih sein, sind aber beide in der tl_member gespeichert. Klar könnte ich miene Tabelle noch etwas &amp;quot;zerlegen&amp;quot; und schauen das ich den webmaster in eine kleine Tabelle auslagere. Bloß die Frage ist wie sinnvoll es für mich ist. Ich fahre nebenbei kleine Geschwindigkeitstests, da ich die komplette Seite dynamisch lassen muss...naja egal man könnte darauf eingehen, wenn es gewollt ist.&lt;br /&gt;
&lt;br /&gt;
ich wollte darauf hinaus, je spezieller der wunsch ist, desto mehr eigenarbeit ist dabei.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel nehme man das save_callback für ein field. Funktioniert einwandfrei, außer ich definiere vorher ein input_field_callback, dann wird dieses Callback nicht mehr angerührt und ich muss einen Globalen callback ausführen. Und das nur, weil es eigentlich nur ein &amp;quot;anzeigefeld&amp;quot; sein sollte, was automatisch befüllt wird und auch nicht änderbar ist. (Vielleicht ist aber auch genau das der Knackpunkt warum es nicht geht)&lt;br /&gt;
&lt;br /&gt;
so aber lange rede kurzer sinn &lt;br /&gt;
  &lt;br /&gt;
 Zitat von dl1ely   &lt;br /&gt;
Das klingt wie das, was ich gerne für mein &amp;quot;pid&amp;quot;-Feld hätte, d.h. Sortierung nach den Paarnamen, die sich aus  &lt;br /&gt;
der pid ergeben anstatt numerisch nach dem pid-Wert. Leider wirft das einen Fehler in DC_Table.php (Zeile  &lt;br /&gt;
3468 bei TL 2.8.3), wo $keys nicht definiert ist. Wenn ich das richtig sehe, funktioniert das nämlich nur mit  &lt;br /&gt;
hardcodierten &amp;quot;options&amp;quot; im DCA-Record (Zeile 3461), ein options_callback wird dort nicht ausgewertet.&lt;br /&gt;
&lt;br /&gt;
mir ist auch aufgefallen und ich hoffe ich lehne mich nicht zu weit aus dem fenster, aber dieser Treiber scheint älter zu sein. Denn ich finde man merkt bei Typolight die struktur und die üerlegungen dahinter. Es gibt zwei möglichkeiten die DC_table zu erweitern. du kannst(solange es keine sortierung oder filter sein soll) kannst du dort wo du das label definierts und die Felder dafür, Tabellenübergreifend arbeiten.&lt;br /&gt;
&lt;br /&gt;
Denn im Code wird der String nochmal zerlegt. du kannst sozusagen &amp;lt;feldname&amp;gt;:&amp;lt;table_name&amp;gt;.&amp;lt;table_field&amp;gt; sagen, dann macht er nochmal einen DB aufruf und holt diese Information für dich.&lt;br /&gt;
&lt;br /&gt;
Willst du es beim Sortieren haben, gibt es auch dort ein hook, welcher aber leider erst aufgerufen wurde nachdem die DB abgefragt wurde(und auch leider schon sortiert). Nun bekomme ich schon das Ergebniss und kann dieses abändern. An sich ja auch nicht schlecht immerhin noch besser als ids dort stehen zu haben, aber dadurch ist es nur eine &amp;quot;gruppierung&amp;quot; und keine Sortierung mehr. Aber bei genauem überlegen(da ich mir dachte ok...dann halt mein eigener Treiber) glaube ich, das es leider dann nicht mehr trivial und performant sortiert werden kann...ist aber noch nicht ins detail durchdacht.&lt;br /&gt;
&lt;br /&gt;
also bei mir sieht es nun so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
'label' =&amp;gt; array ( &lt;br /&gt;
            'fields'            =&amp;gt; array ('id', 'title', 'url', 'ersteller_id:tl_member.username'), &lt;br /&gt;
            'format'            =&amp;gt; '&amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;#%s&amp;lt;/span&amp;gt; WCard von &amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt;' &lt;br /&gt;
                                    . ' (%s) Empfohlen von: &amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt;', &lt;br /&gt;
            'group_callback'    =&amp;gt; array('WCards', 'listViewGroupCallback') &lt;br /&gt;
        ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
		  &lt;br /&gt;
dass Callback ist für die Nachbearbeitung wenn Sortiert wird. Obwohl ich deine Lösung auch sehr interessant finde und auch heute gleich mal testen werde, ob ich es auch nicht so lösen kann.&lt;br /&gt;
&lt;br /&gt;
Nochmal Danke für deine mühe...auch wenn es schade ist, dass nun &amp;quot;erst&amp;quot;(ist nicht abwertend gemeint) dort bist, da ich gerade nachlesen wollte, was du bezüglich des frontend Inputs tust, da ich mir dort gerade den Kopf zerbreche.&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely'''&lt;br /&gt;
&lt;br /&gt;
Leider kann ich dir mit deinen Ausführungen in der zweiten Hälfte eines Posts nicht so ganz folgen.&lt;br /&gt;
&lt;br /&gt;
Die Notation &amp;quot;feld_A:Tabelle_B.feld_B&amp;quot; im DCA-Record für Tabelle A ist mir gestern erst versehentlich unter die Augen gekommen (Ticket-ID #88). In meinem Fall würde es mir nicht soviel helfen, da ich einen String brauche, der sich aus mehreren Feldern aus Tabelle B zusammensetzt, und das auch noch abhängig von den Inhalten. Ohne eigenen PHP-Code geht es da nicht, darum muss der Label-Callback bleiben.&lt;br /&gt;
&lt;br /&gt;
Bezüglich der Sortierung nach den Values aus dem options_callback habe ich ein Ticket aufgemacht (#1914), und den dort von mir vorgeschlagenene Code in meine eigene DC_Table.php übernommen. Funktioniert bei mir einwandfrei. Ich hoffe, dass Leo meinen Codevorschlag übernimmt und die nächste TL-Version das kann.&lt;br /&gt;
&lt;br /&gt;
Mit meiner Entwicklung wirds noch weitergehen, auch der User-Input im Frontend kommt noch. Leider ist die Freizeit begrenzt, und es ist auch nur ein Freizeitprojekt. Von daher kann ich es leider nicht &amp;quot;runterrattern&amp;quot;. Außerdem dauert das Erstellen jedes Schrittes ca. 1h, mit Tippen, Pasten vom Code in den Post und dem Anfertigen der Screenshots. Aber egal, da muss ich jetzt durch. Das Ende ist in Sicht :-).&lt;br /&gt;
&lt;br /&gt;
'''user: Setsunaa'''&lt;br /&gt;
&lt;br /&gt;
sorry das ich mich unverständlich ausgedrückt habe. Dies ist ein Problem, was häufiger auftritt, da ich ein, wie sagt man, &amp;quot;ein in ein schwarzes Loch hineindenker&amp;quot; bin   . Aber ich versuche mein bestes, also bitte nicht übel nehmen...&lt;br /&gt;
&lt;br /&gt;
Stimmt du setzt deinen String zusammen, dies dachte ich mir auch, als ich dir den Vorschlag geschrieben hatt, aber wollte diesen nicht rausnehmen, da es ja vielleicht anderen helfen kann.&lt;br /&gt;
&lt;br /&gt;
Das mit dem Hook ist glaube ich eher etwas, was nur auftritt, wenn man nach etwas sortieren möchte, wo der eigentliche wert aber in einer anderen Tabelle steht. Wie es bei mir der Fall ist, da es gewünscht ist. Also zumindest wenn man sich nicht an die notation hällt. Da ich dies nicht tun kann(zumindest nicht in der Form, die ich jetzt habe), da ich zwei mal die id eines members in der Tabelle habe.&lt;br /&gt;
&lt;br /&gt;
Also in &amp;quot;meiner&amp;quot; Tabelle steht ein ersteller für die Webseiten Karte, dies ist aber nur die id der tl_member. Wenn ich danach sortieren möchte, wird nur die Zahl aus &amp;quot;meiner&amp;quot; tabelle sortiert und ich habe keine möglichkeit gefunden zu sagen, das er diesen wert vorher mit dem usernamen aus tl_member zu ersetzen. &lt;br /&gt;
&lt;br /&gt;
Leider nur danach, dadurch ist es halt nur eine Gruppierung.&lt;br /&gt;
&lt;br /&gt;
Die Stelle in der DC_Table wo du gerne die Änderung hättest hatte ich schon gesehen, aber als für mich unbrauchbar abgestempelt, da dies mir nicht weiterhilft. Aber vielleicht habe ich auch nur etwas übersehen...&lt;br /&gt;
&lt;br /&gt;
Naja ich muss eh viel selber schreiben, dank (an manchen stellen wirklich unnötige) Abhängigkeiten und Wünsche. &lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely'''&lt;br /&gt;
&lt;br /&gt;
 Zitat von Setsunaa   &lt;br /&gt;
Das mit dem Hook ist glaube ich eher etwas, was nur auftritt, wenn man nach etwas sortieren möchte, wo der  &lt;br /&gt;
eigentliche wert aber in einer anderen Tabelle steht. Wie es bei mir der Fall ist, da es gewünscht ist. Also  &lt;br /&gt;
zumindest wenn man sich nicht an die notation hällt. Da ich dies nicht tun kann(zumindest nicht in der Form,  &lt;br /&gt;
die ich jetzt habe), da ich zwei mal die id eines members in der Tabelle habe.&lt;br /&gt;
&lt;br /&gt;
Also in &amp;quot;meiner&amp;quot; Tabelle steht ein ersteller für die Webseiten Karte, dies ist aber nur die id der tl_member.  &lt;br /&gt;
Wenn ich danach sortieren möchte, wird nur die Zahl aus &amp;quot;meiner&amp;quot; tabelle sortiert und ich habe keine  &lt;br /&gt;
möglichkeit gefunden zu sagen, das er diesen wert vorher mit dem usernamen aus tl_member zu ersetzen.  &lt;br /&gt;
Leider nur danach, dadurch ist es halt nur eine Gruppierung.&lt;br /&gt;
Und das findInSet zusammen mit einem Options-Callback hilft dir nicht? Kann deinen konkreten Fall da gerade &lt;br /&gt;
nicht überschauen. Wie gesagt, bei mir löst es mein Problem...&lt;br /&gt;
&lt;br /&gt;
'''user: Setsunaa '''&lt;br /&gt;
&lt;br /&gt;
hmm...wäre möglich, aber ich empfinde es als unschön und mein erster Gedanke dabei war, wie performant ist es, ab einer gewissen User Zahl. Denn dieses Callback würde wenn dann bei jedem einzelnen ausgeführt werden müssen. Aber es könnte auch ganz einfach sein, ich schau mir deine Lösung noch an. Danke für den Hinweiß.&lt;br /&gt;
&lt;br /&gt;
Naja ist ersteinmal nicht so wichtig, das kann ich noch später ändern...und wenn es soll eh mehr über das Frontend gemacht werden, dafür muss ich eh noch einen &amp;quot;Admin&amp;quot; Bereich bauen...&lt;br /&gt;
&lt;br /&gt;
Welches mir heute wirklich Kopfschmerzen bereitet....vorallem durch den Spruch &amp;quot;keep it simpel&amp;quot; und dann hat man kleinigkeiten, die echt nicht leicht zu lösen sind...naja einfach nur speziell   &lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely'''&lt;br /&gt;
&lt;br /&gt;
 Zitat von dl1ely   &lt;br /&gt;
Bezüglich der Sortierung nach den Values aus dem options_callback habe ich ein Ticket aufgemacht (#1914), und den dort von mir vorgeschlagenene Code in meine eigene DC_Table.php übernommen. Funktioniert bei mir einwandfrei. Ich hoffe, dass Leo meinen Codevorschlag übernimmt und die nächste TL-Version das kann.&lt;br /&gt;
&lt;br /&gt;
Juchu:&lt;br /&gt;
* Status wurde geändert von New zu Accepted.&lt;br /&gt;
* Zielversion wurde gesetzt auf 2.9.0.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-12_Backend_Callback-Magie</id>
		<title>TEE-12 Backend Callback-Magie</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-12_Backend_Callback-Magie"/>
				<updated>2010-07-07T21:19:44Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Callb…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Callback-Magie=&lt;br /&gt;
Ja, nach langer Pause geht es wirklich weiter. Diesmal wird die Backendpflege der &amp;quot;Meldungen&amp;quot;-Tabelle komplettiert. Gegenüber dem letzten Schritt haben sich nach fruchtbarer Diskussion einige Änderungen ergeben.&lt;br /&gt;
&lt;br /&gt;
Zunächst die Datenbankdefinition der Tabelle ''tl_gw_meldungen'' in ''system/modules/tl_gw_turnierpaare/config/database.sql'':&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-- &lt;br /&gt;
-- Table `tl_gw_meldungen`&lt;br /&gt;
-- &lt;br /&gt;
CREATE TABLE `tl_gw_meldungen` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `pid` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `datum` varchar(10) NOT NULL default '',&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '',&lt;br /&gt;
  `startklasse` varchar(12) NOT NULL default '',&lt;br /&gt;
  `lat_std` char(32) NOT NULL default '',&lt;br /&gt;
  `turnierort` varchar(128) NOT NULL default '',&lt;br /&gt;
  `turnierart` varchar(64) NULL default NULL,&lt;br /&gt;
  `anzahlpaare` int(4) NULL default NULL,&lt;br /&gt;
  `platz_von` int(4) NULL default NULL,&lt;br /&gt;
  `platz_bis` int(4) NULL default NULL,&lt;br /&gt;
  `bemerkung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
  KEY `pid` (`pid`)&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Feld datum war vorher vom Typ ''date'', aber das funktioniert so nicht, wenn man es als Datumsfeld im Backend verwenden will. Darum jetzt ein ''varchar(10)''. Der Rest blieb unverändert.&lt;br /&gt;
&lt;br /&gt;
Auch das Einfügen der Backendmodule in die Auswahlleiste auf der linken Seite des Backends ändere ich in ''/system/modules/tl_gw_turnierpaare/config/config.php'' ab:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Back end module &lt;br /&gt;
array_insert($GLOBALS['BE_MOD'], 0, array( &lt;br /&gt;
    'gw_paarverwaltung' =&amp;gt; array( &lt;br /&gt;
      'gw_turnierpaare' =&amp;gt; array &lt;br /&gt;
      ( &lt;br /&gt;
        'tables' =&amp;gt; array('tl_gw_turnierpaare'), &lt;br /&gt;
        'icon'   =&amp;gt; 'system/modules/gw_turnierpaare/icons/turnierpaare.png' &lt;br /&gt;
      ), &lt;br /&gt;
      'gw_meldungen' =&amp;gt; array &lt;br /&gt;
      ( &lt;br /&gt;
        'tables' =&amp;gt; array('tl_gw_meldungen'), &lt;br /&gt;
        'icon'   =&amp;gt; 'system/modules/gw_turnierpaare/icons/meldeliste.png' &lt;br /&gt;
      ) &lt;br /&gt;
    ) &lt;br /&gt;
  ) &lt;br /&gt;
);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Durch das ''array_insert'' kann ich mit zweiten Parameter steuern, an welcher Stelle das als letzter Parameter angegebene Array eingefügt werden soll. Bei einer &amp;quot;0&amp;quot; wie hier wandern meine Arrayeinträge ganz nach oben,bei einer &amp;quot;1&amp;quot; an zweite Stelle, usw. Da in der Praxis auf der Webseite häufiger neue Turnierpaarmeldungen eingegeben werden als neue Artikel, mächte ich die Turnierpaarverwaltung gerne ganz oben haben.&lt;br /&gt;
&lt;br /&gt;
Und dadurch, dass ich in dem Array was ich einfüge eine zusätzliche Ebene ''gw_paarverwaltung'' habe, gruppiere ich die beiden Einträge ''gw_turnierpaare'' und ''gw_meldungen'' in eine Untergruppe innerhalb des Menüs. Das schafft mehr Übersicht.&lt;br /&gt;
&lt;br /&gt;
Um die Language-Datei für diese Einträge muss ich mich jetzt auch einmal kümmern (''/system/modules/tl_gw_turnierpaare/languages/modules.php''):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Back end modules &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['gw_turnierpaare'] = array('Turnierpaare', 'Verwaltung der Turnierpaare.'); &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['gw_meldungen'] = array('Meldungen', 'Verwaltung der Turniermeldungen (Meldeliste).'); &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['gw_paarverwaltung'] = 'Paarverwaltung';  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''ACHTUNG''': Während die Language-Einträge für die Module selbst ein Array bestehend aus dem Label des Menüeintrags und dem Beschreibungstext des Moduls sein müssen, ist der Label für die Überschrift der Gruppe im Menü (''gw_paarverwaltung'') nur ein einfacher String!&lt;br /&gt;
&lt;br /&gt;
Wie sieht das nun aus?&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_31.png]]&lt;br /&gt;
&lt;br /&gt;
Wo wir schonmal bei den Language-Dateien sind, machen wir auch noch die Label für die Felder des Backendmoduls  (''/system/modules/tl_gw_turnierpaare/languages/de/tl_gw_meldungen.php''):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php if (!defined('TL_ROOT')) die('You can not access this file directly!'); &lt;br /&gt;
/** &lt;br /&gt;
 * Fields &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['pid'] = array('Paar', 'Turnierpaar auswählen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['datum'] = array('Turnierdatum', 'Turnierdatum eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierort'] = array('Turnierort', 'Turnierort eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierart'] = array('Turnierform', 'Turnierform auswählen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['startgruppe'] = array('Startgruppe', 'Startgruppe auswählen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['startklasse'] = array('Startklasse', 'Startklasse auswählen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['lat_std'] = array('Latein/Standard', 'Tanzart auswählen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['anzahlpaare'] = array('Anzahl gestarteter Paare', 'Die Paaranzahl des Turniers eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_von'] = array('Platz', 'Erzielter Platz'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_bis'] = array('Platz bis', 'Geteilter Platz: Platz bis... - sonst leer lassen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['bemerkung'] = array('Bemerkung', 'Bemerkung eingeben'); &lt;br /&gt;
/** &lt;br /&gt;
 * Reference &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['couple_legend'] = 'Paar'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['tournament_legend'] = 'Turnier'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['result_legend'] = 'Ergebnis'; &lt;br /&gt;
/** &lt;br /&gt;
 * Buttons &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['new']    = array('Neue Meldung', 'Eine neue Turniermeldung anlegen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['edit']   = array('Editieren', 'Die Turniermeldung editieren'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['copy']   = array('Meldung kopieren', 'Die Turniermeldung in die Zwischenablage kopieren'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['delete'] = array('Meldung löschen', 'Die Turniermeldung aus der Liste entfernen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_meldungen']['show']   = array('Details', 'Die Detailansicht der Turniermeldung anzeigen'); &lt;br /&gt;
?&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da muss ich wohl nicht mehr viel zu schreiben: Der erste Block sind Label und Beschreibungen für die Eingabefelder, der zweite Block sind die Label für die Palettenüberschriften, und die dritte Gruppe schließlich die Label und Beschreibungen für die &amp;quot;Aktionsbuttons&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Kommen wir zum spannenden Teil, mir dem ich im Schritt 11 ja noch einen Kampf zu fechten hatte: der DCA-Record  (''/system/modules/tl_gw_turnierpaare/dca/tl_gw_meldungen.php''):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php if (!defined('TL_ROOT')) die('You can not access this file directly!'); &lt;br /&gt;
/** &lt;br /&gt;
 * Table tl_gw_meldungen  &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_DCA']['tl_gw_meldungen'] = array &lt;br /&gt;
( &lt;br /&gt;
    // Config &lt;br /&gt;
    'config' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'dataContainer'               =&amp;gt; 'Table', &lt;br /&gt;
        'enableVersioning'            =&amp;gt; true, &lt;br /&gt;
    ), &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier so weit nichts Spannendes: Weiterhin wird eine Tabelle bearbeitet, und ich aktiviere Versionierung.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // List &lt;br /&gt;
    'list' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'sorting' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'mode'                    =&amp;gt; 2, &lt;br /&gt;
            'fields'                  =&amp;gt; array('datum DESC', 'turnierort', 'pid'), &lt;br /&gt;
            'panelLayout'             =&amp;gt; 'filter;sort,search,limit' &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
mode = 2 bedeutet, dass das Sortierfeld im Header der Tabelle wählbar ist, defaultmäßig sortiere ich nach Turnierdatum (Jüngste ganz oben), dann dem Ort, und schließlich der Paar-ID.&lt;br /&gt;
&lt;br /&gt;
Mit ''panelLayout'' aktiviere ich die Paletten oben am Kopf der Tabelle, um das Sortierfeld wählbar zu machen, das Suchfeld zu aktivieren und die Anzahl der Treffer limitieren zu können.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'label' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'fields'                  =&amp;gt; array('datum','turnierort', 'turnierart', 'startgruppe','startklasse','lat_std'), &lt;br /&gt;
            'format'                  =&amp;gt; '%s - #name# - &amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt; - &amp;lt;span style=&amp;quot;color: #section_colour#;&amp;quot;&amp;gt;%s %s %s %s&amp;lt;/span&amp;gt;', &lt;br /&gt;
            'label_callback'          =&amp;gt; array('tl_gw_meldungen', 'lookup_pid') &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So, hier beginnt etwas die Magie...ich bastele mir das Format der Ausgabezeilen für die Backendansicht.&lt;br /&gt;
 &lt;br /&gt;
Leider habe ich hier nur die Felder der aktuellen Tabelle (''tl_gw_meldungen'') zur Verfügung, ich möchte aber gerne den Namen des Paares anzeigen, was zur ''pid'' gehört, die im Datensatz steht (''pid'' ist der Foreign Key in die ''tl_gw_turnierpaare''-Tabelle. Im klassischen SQL würde ich hier also einen JOIN machen). &lt;br /&gt;
&lt;br /&gt;
So direkt geht das leider nicht, darum definiere ich einen ''label_callback'', der weiter unten in dieser Datei als Funktion ''lookup_pid()'' in der Klasse ''tl_gw_meldungen'' definiert wird. Die Felder, die ich jetzt schon habe, definiere ich auch direkt im String. Für den Namen des Paares setze ich zunächst einen Platzhalter &amp;quot;#name#&amp;quot; in den String. &lt;br /&gt;
&lt;br /&gt;
Außerdem gibt es noch einen Platzhalter &amp;quot;#section_colour#&amp;quot;. Ich möchte Turnierstarts in der Tanzform Standardtänze in orange darstellen, und solche in der Tanzform Lateinamerikanische Tänze in rot. Das kann ich an dieser Stelle im DCA-Record nicht entscheiden, weil es vom Inhalt des Felds ''lat_std'' abhängt. Auch das wird im ''label_callback'' geregelt.&lt;br /&gt;
&lt;br /&gt;
Die Platzhalter werden im ''label_callback'' durch ein ''str_replace'' mit den gewünschten Werten ersetzt. Schön ist das nicht, aber funktioniert.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'global_operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'all' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['MSC']['all'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=select', &lt;br /&gt;
                'class'               =&amp;gt; 'header_edit_all', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ) &lt;br /&gt;
        ), &lt;br /&gt;
        'operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'edit' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['edit'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=edit', &lt;br /&gt;
                'icon'                =&amp;gt; 'edit.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'copy' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['copy'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=copy', &lt;br /&gt;
                'icon'                =&amp;gt; 'copy.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'delete' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['delete'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=delete', &lt;br /&gt;
                'icon'                =&amp;gt; 'delete.gif', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;if (!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\')) return false; Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ), &lt;br /&gt;
            'show' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['show'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=show', &lt;br /&gt;
                'icon'                =&amp;gt; 'show.gif' &lt;br /&gt;
            ) &lt;br /&gt;
        ) &lt;br /&gt;
    ),  					 &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zu den globalen Operationen gibt es eigentlich nichts zu sagen. Die bleiben so, wie der ''Extension-Creator'' sie angelegt hat...&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '{couple_legend},pid;&lt;br /&gt;
{tournament_legend},datum,turnierort,turnierart,startgruppe,startklas&lt;br /&gt;
                                    .'{result_legend},anzahlpaare,plabis,bemerkung;' &lt;br /&gt;
    ), &lt;br /&gt;
    // Subpalettes &lt;br /&gt;
    'subpalettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        ''                            =&amp;gt; '' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;	 &lt;br /&gt;
	 &lt;br /&gt;
Die Palettendefinition hat sich nicht geändert, und Subpaletten gibt es weiterhin nicht.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'pid' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['pid'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'options_callback'        =&amp;gt; array('tl_gw_meldungen', 'getActiveCouples'), &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true) &lt;br /&gt;
        ), &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
		  &lt;br /&gt;
Das Feld ''pid'' war bisher ein ''foreignKey''-Feld, aber damit konnte ich z.B. nur mit dem Partner-Nachnamen verknüpfen, nicht mit dem Paarnamen. Außerdem wurden hier immer ALLE Paare angezeigt, hier sollen aber nur AKTIVE Paare auswählbar sein. Um das besser machen zu können, definiere ich die Möglichkeiten in der Dropdown-Box selbst durch den ''options_callback'' ''getActiveCouples()'' in der Klasse ''tl_gw_meldungen'', die gleich noch folgt.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'datum' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['datum'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 6,&lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'datepicker'=&amp;gt;$this-&amp;gt;getDatePickerString(), 'tl_class'=&amp;gt;'w50 wizard', 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;10, 'rgxp' =&amp;gt; 'date') &lt;br /&gt;
        ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
		  &lt;br /&gt;
''flag =&amp;gt; 6'' ist hier der große Trick, damit das Timestamp-Format von &amp;quot;datum&amp;quot; richtig als Datum im Format TT.MM.JJJJ angezeigt wird. Abgeguckt habe ich das übrigens im Backend in ''/system/modules/backend/dca/tl_log.php''.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'turnierort' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierort'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 11, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;128, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'turnierart' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierart'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 11, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$TurnierArten, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'startgruppe' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['startgruppe'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 11, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$StartGruppen, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'includeBlankOption' =&amp;gt; true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'startklasse' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['startklasse'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 11, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$StartKlassen, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'lat_std' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['lat_std'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'sorting'                 =&amp;gt; false, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$TanzArten, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'anzahlpaare' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['anzahlpaare'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;4, 'rgxp' =&amp;gt; 'digit') &lt;br /&gt;
        ), &lt;br /&gt;
        'platz_von' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_von'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;4, 'rgxp' =&amp;gt; 'digit', 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'platz_bis' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_bis'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;4, 'rgxp' =&amp;gt; 'digit', 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'bemerkung' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['bemerkung'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'textarea', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'cols' =&amp;gt; 80, 'rows' =&amp;gt; 20, 'allowHtml' =&amp;gt; false) &lt;br /&gt;
        ), &lt;br /&gt;
    ) &lt;br /&gt;
);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier gibt es keine großen Besonderheiten mehr. Gegenüber [[TEE-11_Backend_Zweite_Tabelle|Schritt 11]] habe ich die durchsuchbaren und sortierbaren Felder etwas erweitert bzw. geändert.&lt;br /&gt;
&lt;br /&gt;
Nun kommt die Backendklasse, in der ich die Callbacks unterbringe:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class tl_gw_meldungen extends Backend &lt;br /&gt;
{ &lt;br /&gt;
    /** &lt;br /&gt;
     * Import the back end user object &lt;br /&gt;
     */ &lt;br /&gt;
    public function __construct() &lt;br /&gt;
    { &lt;br /&gt;
        parent::__construct(); &lt;br /&gt;
        $this-&amp;gt;import('BackendUser', 'User'); &lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
	 &lt;br /&gt;
Auftaktgeplänkel...&lt;br /&gt;
&lt;br /&gt;
Zunächst der ''options_callback'', der mir die Liste der aktiven Turnierpaare für die Auswahl in der Dropdown-Box liefert:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  public function getActiveCouples() &lt;br /&gt;
  { &lt;br /&gt;
      $couples = array(); &lt;br /&gt;
        // Get all the active couples 		  &lt;br /&gt;
        $objCouples = $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;SELECT id,partnernachname,partnervorname,partnerinnachname,partnerinvorname FROM tl_gw_turnierpaare WHERE aktiv='1' &lt;br /&gt;
ORDER by partnernachname, partnervorname, partnerinnachname, partnerinvorname&amp;quot;) &lt;br /&gt;
                            -&amp;gt;execute(); &lt;br /&gt;
        while ($objCouples-&amp;gt;next()) &lt;br /&gt;
        { &lt;br /&gt;
            $k = $objCouples-&amp;gt;id; &lt;br /&gt;
            $v = $objCouples-&amp;gt;partnernachname; &lt;br /&gt;
            if($objCouples-&amp;gt;partnervorname) &lt;br /&gt;
            { &lt;br /&gt;
               $v .= ', '.$objCouples-&amp;gt;partnervorname; &lt;br /&gt;
      } &lt;br /&gt;
      if($objCouples-&amp;gt;partnerinnachname) &lt;br /&gt;
      { &lt;br /&gt;
        $v .= ' und '.$objCouples-&amp;gt;partnerinnachname; &lt;br /&gt;
        if($objCouples-&amp;gt;partnerinvorname) &lt;br /&gt;
              { &lt;br /&gt;
                 $v .= ', '.$objCouples-&amp;gt;partnerinvorname; &lt;br /&gt;
        } &lt;br /&gt;
      } &lt;br /&gt;
            $couples[$k] =$v; &lt;br /&gt;
        } &lt;br /&gt;
        return $couples; &lt;br /&gt;
  } &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
Der größte Teil der Funktion ist eigentlich das &amp;quot;Zusammenbasteln&amp;quot; des Paarnamens aus den Einzelbestandteilen der Namen von Partner und Partnerin. Zunächst werden aus der ''tl_gw_turnierpaare''-Tabelle die Namen der aktiven Paare selektiert und der Ergebnisstring daraus zusammengesetzt. Das Ergebnis wird dann einem Array zugewiesen, wobei die ID des Paares der Array-Key ist, und der Paarname der Value - also z.B. $couples[47] = &amp;quot;Wupp, Willi und Wupp, Sieglinde&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In der Dropdownbox steht der String, und wenn ich den dort auswähle, landet die ID 47 als ''pid'' in der Datenbanktabelle ''tl_gw_meldungen''. Und, was noch vieeeeel cooler ist: Wenn ich nach dem ''pid''-Feld sortiere, dann werden auch die Sortierheader durch die entsprechenden Strings ersetzt, statt dass dort der numerische ''pid''-Wert steht. Leider erfolgt die Sortierung natürlich nach dem Key, nicht nach dem Value...aber das wäre ja fast zuviel verlangt :-).&lt;br /&gt;
&lt;br /&gt;
Weiter geht es mit ''label_callback''. Als erstes Argument bekommt der die aktuelle Zeile aus der Datenbank, als zweites Argument den Label, wie er weiter oben im DCA-Record definiert wurde, hier also mit dem Platzhaltern #name# und #section_colour#.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:	&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function lookup_pid($row, $label) &lt;br /&gt;
    { &lt;br /&gt;
        $pid = $row['pid']; &lt;br /&gt;
         &lt;br /&gt;
        // Datensatz mit ID pid aus Tabelle tl_gw_turnierpaare holen &lt;br /&gt;
    $prow = $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;SELECT * FROM tl_gw_turnierpaare WHERE id=?&amp;quot;) &lt;br /&gt;
                              -&amp;gt;execute($pid);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit der pid aus dem aktuellen Datensatz holen wir den Datensatz des Turnierpaares...&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $name = '&amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;'.$prow-&amp;gt;partnernachname.'&amp;lt;/span&amp;gt;'; &lt;br /&gt;
    if($prow-&amp;gt;partnervorname) &lt;br /&gt;
    { &lt;br /&gt;
      $name .= ', '.$prow-&amp;gt;partnervorname; &lt;br /&gt;
    }; &lt;br /&gt;
    if($prow-&amp;gt;partnerinnachname) &lt;br /&gt;
    { &lt;br /&gt;
      $name .= ' und &amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;'.$prow-&amp;gt;partnerinnachname.'&amp;lt;/span&amp;gt;'; &lt;br /&gt;
      if($prow-&amp;gt;partnerinvorname) &lt;br /&gt;
      { &lt;br /&gt;
        $name .= ', '.$prow-&amp;gt;partnerinvorname; &lt;br /&gt;
      } &lt;br /&gt;
    };  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...und bauen aus den Namensbestandteilen den Paarnamen zusammen, wobei die Nachnamen fett erscheinen sollen.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $colour = 'black'; &lt;br /&gt;
    switch($row['lat_std']) &lt;br /&gt;
    { &lt;br /&gt;
      case 'Std': &lt;br /&gt;
        $colour = 'orange'; &lt;br /&gt;
        break; &lt;br /&gt;
      case 'Lat': &lt;br /&gt;
        $colour = 'red'; &lt;br /&gt;
        break; &lt;br /&gt;
    }  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In Abhängigkeit vom Inhalt des ''lat_std''-Feldes wird eine Farbe zugewiesen. Falls der Inhalt unbekannt ist, bleibt die Schrift schwarz.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $label = str_replace('#section_colour#', $colour, $label); &lt;br /&gt;
     &lt;br /&gt;
    $label = str_replace('#name#', $name, $label); &lt;br /&gt;
     &lt;br /&gt;
    return $label; &lt;br /&gt;
  } &lt;br /&gt;
};   &lt;br /&gt;
?&amp;gt;  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wir ersetzen die Platzhalter #name# und #section_colour# im Label-String durch die neu berechneten Werte, und geben den Label zurück.&lt;br /&gt;
&lt;br /&gt;
Was haben wir damit nun erreicht:&lt;br /&gt;
				&lt;br /&gt;
[[Datei:gw_turnierpaare_32.png]]&lt;br /&gt;
&lt;br /&gt;
Unsere Startmeldungen sind nach dem Datum sortiert, die Nachnamen im Paarnamen sind fett, die Stadt auch, und die &amp;quot;Kategorisierung&amp;quot; des Turniers ist orange oder rot, je nachdem ob es um Standardtänze oder lateinamerikanische Tänze geht.&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_33.png]]&lt;br /&gt;
&lt;br /&gt;
Sortieren wir nach den Paaren, dann wird die numerische pid in den Sortierheader durch unseren options_callback in die entsprechenden Strings umgesetzt - sehr nett. Leider erfolgt die Sortierung weiterhin numerisch nach der pid, und nicht alphabetisch nach den Strings. Vielleicht hat jemand noch eine Idee, wie man das lösen könnte?&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_34.png]]&lt;br /&gt;
&lt;br /&gt;
Und bei Neuanlage einer Turniermeldung werden in der Dropdown-Liste nurnoch die aktiven Paare aufgeführt, nicht mehr ALLE.&lt;br /&gt;
&lt;br /&gt;
Im nächsten Schritt geht es ans Frontendmodul für die Meldeliste... &lt;br /&gt;
&lt;br /&gt;
Ich bin gerade in der DCA-Referenz über das Feld ''findInSet'' unter ''eval'' gestolpert: &amp;quot;Sort by the actual option values instead of their labels (available from version 2.7.RC1).&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Das klingt wie das, was ich gerne für mein ''pid''-Feld hätte, d.h. Sortierung nach den Paarnamen, die sich aus der ''pid'' ergeben anstatt numerisch nach dem ''pid''-Wert. Leider wirft das einen Fehler in ''DC_Table.php'' (Zeile 3468 bei TL 2.8.3), wo ''$keys'' nicht definiert ist. Wenn ich das richtig sehe, funktioniert das nämlich nur mit hardcodierten &amp;quot;options&amp;quot; im DCA-Record (Zeile 3461), ein ''options_callback'' wird dort nicht ausgewertet.&lt;br /&gt;
&lt;br /&gt;
Kann das einer der &amp;quot;Profis&amp;quot; bestätigen? Wäre das dann nicht evtl. ein kleiner lohnenswerter Punkt für einen Feature-Request? Sieht für mich nach einem Zweizeiler der Marke &amp;quot;Falls options nicht gesetzt ist options_callback ausführen, dann weitermachen&amp;quot; aus.&lt;br /&gt;
&lt;br /&gt;
'''EDIT''': Ich habe mal ein Ticket dafür gemacht: http://dev.typolight.org/issues/1914&lt;br /&gt;
Habe meine ''DC_Table.php'' entsprechend angepasst, und damit funktioniert es bei mir wie gewünscht.&lt;br /&gt;
&lt;br /&gt;
==Diskussion aus dem Forum==&lt;br /&gt;
{{Hinweis|Die Wiedergabe folgt dem Forums-Thread, der verschiedene Thematiken aufwirft. Sie muss daher noch umgearbeitet werden.}}&lt;br /&gt;
&lt;br /&gt;
'''user: Setsunaa'''&lt;br /&gt;
&lt;br /&gt;
Ich Entwickel seit zwei Monaten an einem Webseiten Katalog und wusste echt nicht was da auf mich zu kommt. Leider sind solche Art von &amp;quot;Katalogen&amp;quot; eher weniger vertreten und auch die catalouge extension für meine Dienste doch etwas zu überladen ist(da ich nix verkaufe) musste ich mich mit den gleichen Sachen asueinandersetzen und dein Tagebuch war eine große hilfe.&lt;br /&gt;
&lt;br /&gt;
auch wenn ich oft geflucht ahbe, denn bei dir funktionierten Sachen, die ich etwas umständlciher machen musste. Was aber auch an meiner Datenbank struktur liegt. Hällt man sich nicht an die gedachten Strukturen, muss man einiges nachimplementieren. Um genauer zu sein ist es für mein vorhaben nicht so simpel nur 1:n beziheungen zu finden. &lt;br /&gt;
&lt;br /&gt;
Zum Verständniss: eine Webseite hat einen ersteller/empfehler und einen Webmaster/Kontaktperson. Diese können gleich aber auch unterschiedlcih sein, sind aber beide in der tl_member gespeichert. Klar könnte ich miene Tabelle noch etwas &amp;quot;zerlegen&amp;quot; und schauen das ich den webmaster in eine kleine Tabelle auslagere. Bloß die Frage ist wie sinnvoll es für mich ist. Ich fahre nebenbei kleine Geschwindigkeitstests, da ich die komplette Seite dynamisch lassen muss...naja egal man könnte darauf eingehen, wenn es gewollt ist.&lt;br /&gt;
&lt;br /&gt;
ich wollte darauf hinaus, je spezieller der wunsch ist, desto mehr eigenarbeit ist dabei.&lt;br /&gt;
&lt;br /&gt;
Als Beispiel nehme man das save_callback für ein field. Funktioniert einwandfrei, außer ich definiere vorher ein input_field_callback, dann wird dieses Callback nicht mehr angerührt und ich muss einen Globalen callback ausführen. Und das nur, weil es eigentlich nur ein &amp;quot;anzeigefeld&amp;quot; sein sollte, was automatisch befüllt wird und auch nicht änderbar ist. (Vielleicht ist aber auch genau das der Knackpunkt warum es nicht geht)&lt;br /&gt;
&lt;br /&gt;
so aber lange rede kurzer sinn &lt;br /&gt;
  &lt;br /&gt;
 Zitat von dl1ely   &lt;br /&gt;
Das klingt wie das, was ich gerne für mein &amp;quot;pid&amp;quot;-Feld hätte, d.h. Sortierung nach den Paarnamen, die sich aus  &lt;br /&gt;
der pid ergeben anstatt numerisch nach dem pid-Wert. Leider wirft das einen Fehler in DC_Table.php (Zeile  &lt;br /&gt;
3468 bei TL 2.8.3), wo $keys nicht definiert ist. Wenn ich das richtig sehe, funktioniert das nämlich nur mit  &lt;br /&gt;
hardcodierten &amp;quot;options&amp;quot; im DCA-Record (Zeile 3461), ein options_callback wird dort nicht ausgewertet.&lt;br /&gt;
&lt;br /&gt;
mir ist auch aufgefallen und ich hoffe ich lehne mich nicht zu weit aus dem fenster, aber dieser Treiber scheint älter zu sein. Denn ich finde man merkt bei Typolight die struktur und die üerlegungen dahinter. Es gibt zwei möglichkeiten die DC_table zu erweitern. du kannst(solange es keine sortierung oder filter sein soll) kannst du dort wo du das label definierts und die Felder dafür, Tabellenübergreifend arbeiten.&lt;br /&gt;
&lt;br /&gt;
Denn im Code wird der String nochmal zerlegt. du kannst sozusagen &amp;lt;feldname&amp;gt;:&amp;lt;table_name&amp;gt;.&amp;lt;table_field&amp;gt; sagen, dann macht er nochmal einen DB aufruf und holt diese Information für dich.&lt;br /&gt;
&lt;br /&gt;
Willst du es beim Sortieren haben, gibt es auch dort ein hook, welcher aber leider erst aufgerufen wurde nachdem die DB abgefragt wurde(und auch leider schon sortiert). Nun bekomme ich schon das Ergebniss und kann dieses abändern. An sich ja auch nicht schlecht immerhin noch besser als ids dort stehen zu haben, aber dadurch ist es nur eine &amp;quot;gruppierung&amp;quot; und keine Sortierung mehr. Aber bei genauem überlegen(da ich mir dachte ok...dann halt mein eigener Treiber) glaube ich, das es leider dann nicht mehr trivial und performant sortiert werden kann...ist aber noch nicht ins detail durchdacht.&lt;br /&gt;
&lt;br /&gt;
also bei mir sieht es nun so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
'label' =&amp;gt; array ( &lt;br /&gt;
            'fields'            =&amp;gt; array ('id', 'title', 'url', 'ersteller_id:tl_member.username'), &lt;br /&gt;
            'format'            =&amp;gt; '&amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;#%s&amp;lt;/span&amp;gt; WCard von &amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt;' &lt;br /&gt;
                                    . ' (%s) Empfohlen von: &amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt;', &lt;br /&gt;
            'group_callback'    =&amp;gt; array('WCards', 'listViewGroupCallback') &lt;br /&gt;
        ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
		  &lt;br /&gt;
dass Callback ist für die Nachbearbeitung wenn Sortiert wird. Obwohl ich deine Lösung auch sehr interessant finde und auch heute gleich mal testen werde, ob ich es auch nicht so lösen kann.&lt;br /&gt;
&lt;br /&gt;
Nochmal Danke für deine mühe...auch wenn es schade ist, dass nun &amp;quot;erst&amp;quot;(ist nicht abwertend gemeint) dort bist, da ich gerade nachlesen wollte, was du bezüglich des frontend Inputs tust, da ich mir dort gerade den Kopf zerbreche.&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely'''&lt;br /&gt;
&lt;br /&gt;
Leider kann ich dir mit deinen Ausführungen in der zweiten Hälfte eines Posts nicht so ganz folgen.&lt;br /&gt;
&lt;br /&gt;
Die Notation &amp;quot;feld_A:Tabelle_B.feld_B&amp;quot; im DCA-Record für Tabelle A ist mir gestern erst versehentlich unter die Augen gekommen (Ticket-ID #88). In meinem Fall würde es mir nicht soviel helfen, da ich einen String brauche, der sich aus mehreren Feldern aus Tabelle B zusammensetzt, und das auch noch abhängig von den Inhalten. Ohne eigenen PHP-Code geht es da nicht, darum muss der Label-Callback bleiben.&lt;br /&gt;
&lt;br /&gt;
Bezüglich der Sortierung nach den Values aus dem options_callback habe ich ein Ticket aufgemacht (#1914), und den dort von mir vorgeschlagenene Code in meine eigene DC_Table.php übernommen. Funktioniert bei mir einwandfrei. Ich hoffe, dass Leo meinen Codevorschlag übernimmt und die nächste TL-Version das kann.&lt;br /&gt;
&lt;br /&gt;
Mit meiner Entwicklung wirds noch weitergehen, auch der User-Input im Frontend kommt noch. Leider ist die Freizeit begrenzt, und es ist auch nur ein Freizeitprojekt. Von daher kann ich es leider nicht &amp;quot;runterrattern&amp;quot;. Außerdem dauert das Erstellen jedes Schrittes ca. 1h, mit Tippen, Pasten vom Code in den Post und dem Anfertigen der Screenshots. Aber egal, da muss ich jetzt durch. Das Ende ist in Sicht :-).&lt;br /&gt;
&lt;br /&gt;
'''user: Setsunaa'''&lt;br /&gt;
&lt;br /&gt;
sorry das ich mich unverständlich ausgedrückt habe. Dies ist ein Problem, was häufiger auftritt, da ich ein, wie sagt man, &amp;quot;ein in ein schwarzes Loch hineindenker&amp;quot; bin   . Aber ich versuche mein bestes, also bitte nicht übel nehmen...&lt;br /&gt;
&lt;br /&gt;
Stimmt du setzt deinen String zusammen, dies dachte ich mir auch, als ich dir den Vorschlag geschrieben hatt, aber wollte diesen nicht rausnehmen, da es ja vielleicht anderen helfen kann.&lt;br /&gt;
&lt;br /&gt;
Das mit dem Hook ist glaube ich eher etwas, was nur auftritt, wenn man nach etwas sortieren möchte, wo der eigentliche wert aber in einer anderen Tabelle steht. Wie es bei mir der Fall ist, da es gewünscht ist. Also zumindest wenn man sich nicht an die notation hällt. Da ich dies nicht tun kann(zumindest nicht in der Form, die ich jetzt habe), da ich zwei mal die id eines members in der Tabelle habe.&lt;br /&gt;
&lt;br /&gt;
Also in &amp;quot;meiner&amp;quot; Tabelle steht ein ersteller für die Webseiten Karte, dies ist aber nur die id der tl_member. Wenn ich danach sortieren möchte, wird nur die Zahl aus &amp;quot;meiner&amp;quot; tabelle sortiert und ich habe keine möglichkeit gefunden zu sagen, das er diesen wert vorher mit dem usernamen aus tl_member zu ersetzen. &lt;br /&gt;
&lt;br /&gt;
Leider nur danach, dadurch ist es halt nur eine Gruppierung.&lt;br /&gt;
&lt;br /&gt;
Die Stelle in der DC_Table wo du gerne die Änderung hättest hatte ich schon gesehen, aber als für mich unbrauchbar abgestempelt, da dies mir nicht weiterhilft. Aber vielleicht habe ich auch nur etwas übersehen...&lt;br /&gt;
&lt;br /&gt;
Naja ich muss eh viel selber schreiben, dank (an manchen stellen wirklich unnötige) Abhängigkeiten und Wünsche. &lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely'''&lt;br /&gt;
&lt;br /&gt;
 Zitat von Setsunaa   &lt;br /&gt;
Das mit dem Hook ist glaube ich eher etwas, was nur auftritt, wenn man nach etwas sortieren möchte, wo der  &lt;br /&gt;
eigentliche wert aber in einer anderen Tabelle steht. Wie es bei mir der Fall ist, da es gewünscht ist. Also  &lt;br /&gt;
zumindest wenn man sich nicht an die notation hällt. Da ich dies nicht tun kann(zumindest nicht in der Form,  &lt;br /&gt;
die ich jetzt habe), da ich zwei mal die id eines members in der Tabelle habe.&lt;br /&gt;
&lt;br /&gt;
Also in &amp;quot;meiner&amp;quot; Tabelle steht ein ersteller für die Webseiten Karte, dies ist aber nur die id der tl_member.  &lt;br /&gt;
Wenn ich danach sortieren möchte, wird nur die Zahl aus &amp;quot;meiner&amp;quot; tabelle sortiert und ich habe keine  &lt;br /&gt;
möglichkeit gefunden zu sagen, das er diesen wert vorher mit dem usernamen aus tl_member zu ersetzen.  &lt;br /&gt;
Leider nur danach, dadurch ist es halt nur eine Gruppierung.&lt;br /&gt;
Und das findInSet zusammen mit einem Options-Callback hilft dir nicht? Kann deinen konkreten Fall da gerade &lt;br /&gt;
nicht überschauen. Wie gesagt, bei mir löst es mein Problem...&lt;br /&gt;
&lt;br /&gt;
'''user: Setsunaa '''&lt;br /&gt;
&lt;br /&gt;
hmm...wäre möglich, aber ich empfinde es als unschön und mein erster Gedanke dabei war, wie performant ist es, ab einer gewissen User Zahl. Denn dieses Callback würde wenn dann bei jedem einzelnen ausgeführt werden müssen. Aber es könnte auch ganz einfach sein, ich schau mir deine Lösung noch an. Danke für den Hinweiß.&lt;br /&gt;
&lt;br /&gt;
Naja ist ersteinmal nicht so wichtig, das kann ich noch später ändern...und wenn es soll eh mehr über das Frontend gemacht werden, dafür muss ich eh noch einen &amp;quot;Admin&amp;quot; Bereich bauen...&lt;br /&gt;
&lt;br /&gt;
Welches mir heute wirklich Kopfschmerzen bereitet....vorallem durch den Spruch &amp;quot;keep it simpel&amp;quot; und dann hat man kleinigkeiten, die echt nicht leicht zu lösen sind...naja einfach nur speziell   &lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely'''&lt;br /&gt;
&lt;br /&gt;
 Zitat von dl1ely   &lt;br /&gt;
Bezüglich der Sortierung nach den Values aus dem options_callback habe ich ein Ticket aufgemacht (#1914), und den dort von mir vorgeschlagenene Code in meine eigene DC_Table.php übernommen. Funktioniert bei mir einwandfrei. Ich hoffe, dass Leo meinen Codevorschlag übernimmt und die nächste TL-Version das kann.&lt;br /&gt;
&lt;br /&gt;
Juchu:&lt;br /&gt;
* Status wurde geändert von New zu Accepted.&lt;br /&gt;
* Zielversion wurde gesetzt auf 2.9.0.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-11_Backend_Zweite_Tabelle</id>
		<title>TEE-11 Backend Zweite Tabelle</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-11_Backend_Zweite_Tabelle"/>
				<updated>2010-07-07T20:58:45Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Die z…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Die zweite Tabelle=&lt;br /&gt;
Ich habe mich lange davor gedrückt, aber jetzt muss es an meine zweite Tabelle gehen: ''tl_gw_meldungen''.&lt;br /&gt;
&lt;br /&gt;
Meldungen sind Teilnahmen von Turnierpaaren an Turnieren. Sie bestehen aus &lt;br /&gt;
* dem Datum der Turnierteilnahme, &lt;br /&gt;
* dem Ort, &lt;br /&gt;
* der Startgruppe (Altersklasse) und der Startklasse (aus regeltechnischen Gründen müssen die NICHT zwingend mit den entsprechenden Werten, die beim Turnierpaar eingetragen sind übereinstimmen), &lt;br /&gt;
* der Tanzart (Standard/Lateinamerikanisch), &lt;br /&gt;
* der Turnierart (hier unterscheidet man &amp;quot;offene Turniere&amp;quot;, &amp;quot;Einladungsturniere&amp;quot;, &amp;quot;Landesmeisterschaften&amp;quot;, &amp;quot;Deutsche Meisterschaften&amp;quot; usw), &lt;br /&gt;
* der Anzahl der gestarteten Paare, &lt;br /&gt;
* dem Platz (da es geteilte Plätze wie 5.-7. geben kann gibt es ''platz_von'' und ''platz_bis''), und &lt;br /&gt;
* einem Freitext als Bemerkung.&lt;br /&gt;
&lt;br /&gt;
Soviel zur Domain specific knowledge.&lt;br /&gt;
&lt;br /&gt;
Schauen wir uns nochmal die SQL-Definition in ''config/database.sql'' an:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-- &lt;br /&gt;
-- Table `tl_gw_meldungen`&lt;br /&gt;
-- &lt;br /&gt;
CREATE TABLE `tl_gw_meldungen` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `pid` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `datum` date NOT NULL default '2000-01-01',&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '',&lt;br /&gt;
  `startklasse` varchar(12) NOT NULL default '',&lt;br /&gt;
  `lat_std` char(32) NOT NULL default '',&lt;br /&gt;
  `turnierort` varchar(128) NOT NULL default '',&lt;br /&gt;
  `turnierart` varchar(64) NULL default NULL,&lt;br /&gt;
  `anzahlpaare` int(4) NULL default NULL,&lt;br /&gt;
  `platz_von` int(4) NULL default NULL,&lt;br /&gt;
  `platz_bis` int(4) NULL default NULL,&lt;br /&gt;
  `bemerkung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
  KEY `pid` (`pid`)&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ersten 4 Felder sind ja so &amp;quot;default&amp;quot;. Hier macht ''pid'' (Parent-ID) aber auch Sinn. Die Meldungen sind &amp;quot;Childs&amp;quot; der Turnierpaare. Im Backend wollte ich auch so vorgehen, also bei den Turnierpaaren auf einen Tree-View umstellen. Im DCA-Record für ''tl_gw_turnierpaare'' habe ich also unter ''sort'' den ''mode'' auf 5 gestellt, und im DCA-Record für ''tl_gw_meldungen'' auf 6.&lt;br /&gt;
&lt;br /&gt;
Dann straft mich TYPOlight aber mit der SQL-Fehlermeldung, dass es in der Tabelle ''tl_gw_turnierpaare'' kein Feld ''pid'' gäbe. Richtig, gibt es auch nicht. Da das die Parent-Tabelle ist, braucht die auch kein ''pid''. Nun gut, offensichtlich erfordert die Logik das so, also erfülle ich den Wunsch und spendiere auch ''tl_gw_turnierpaare'' ein Feld ''pid''. &lt;br /&gt;
&lt;br /&gt;
Beim Betrachten im Backend fällt mir aber auf, dass das unpraktisch ist: Der Sportwart, der das im Backend pflegt, den interessiert nur die nach dem Turnierdatum sortierte Liste, neueste ganz oben. Der will gar nicht erst das Turnierpaar suchen, um dort eine Meldung einzugeben.&lt;br /&gt;
&lt;br /&gt;
Ich entscheide mich, Turnierpaare und Meldungen im Backend getrennt zu verwalten, aber bei den Meldungen dann eine foreign-key-Beziehung über die ''pid'' zur Turnierpaartabelle zu haben. Wenn der Sportwart eine neue Meldung anlegt, soll er über ein Dropdown das Turnierpaar auswählen, zu dem diese Meldung gehört, die Liste selbst soll aber nach dem Datum absteigend sortiert sein.&lt;br /&gt;
&lt;br /&gt;
Ich brauche also eine weitere Seite im Backend, und modifiziere ''/system/modules/gw_turnierpaare/config/config.php'' auf:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Back end module &lt;br /&gt;
$GLOBALS['BE_MOD']['content']['gw_turnierpaare'] = array &lt;br /&gt;
( &lt;br /&gt;
    'tables' =&amp;gt; array('tl_gw_turnierpaare'), &lt;br /&gt;
    'icon'   =&amp;gt; 'system/modules/gw_turnierpaare/icons/turnierpaare.png' &lt;br /&gt;
); &lt;br /&gt;
$GLOBALS['BE_MOD']['content']['gw_meldungen'] = array &lt;br /&gt;
( &lt;br /&gt;
    'tables' =&amp;gt; array('tl_gw_meldungen'), &lt;br /&gt;
    'icon'   =&amp;gt; 'system/modules/gw_turnierpaare/icons/meldeliste.png' &lt;br /&gt;
);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also zwei hier formal getrennte Tabellen mit getrennten Backendseiten und verschiedenen Icons ([[Datei:gw_meldeliste.png|meldeliste.png]] hänge ich hier an, das soll ein Siegerpodest darstellen).&lt;br /&gt;
&lt;br /&gt;
Dann gehts an DCA für die Meldungstabelle, in ''/system/modules/gw_turnierpaare/dca/tl_gw_meldungen.php'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Table tl_gw_meldungen  &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_DCA']['tl_gw_meldungen'] = array &lt;br /&gt;
( &lt;br /&gt;
    // Config &lt;br /&gt;
    'config' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'dataContainer'               =&amp;gt; 'Table', &lt;br /&gt;
        'enableVersioning'            =&amp;gt; true, &lt;br /&gt;
    ), &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
	 &lt;br /&gt;
Hier keine Besonderheiten, es ist eine Tabelle mit Versionierung...&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // List &lt;br /&gt;
    'list' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'sorting' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'mode'                    =&amp;gt; 1, &lt;br /&gt;
            'fields'                  =&amp;gt; array('datum DESC', 'turnierort'), &lt;br /&gt;
            'panelLayout'             =&amp;gt; '', &lt;br /&gt;
            'flag'                    =&amp;gt; 8, &lt;br /&gt;
        ), &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
		  &lt;br /&gt;
Sortierung nach festem Feld, nämlich dem absteigenden Datum, und dann nach dem Turnierort alphabetisch. Das Panel für Sortieren, Filtern usw lasse ich erstmal weg (Das sorgte nämlich für eine kryptische Fehlermeldung - ich kümmere mich später darum). ''flag'' 8 ist das absteigende Sortieren nach dem Monat. Zu meinem Problem damit komme ich später.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'label' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'fields'                  =&amp;gt; array('datum', 'turnierort', 'turnierart', 'startgruppe','startklasse','lat_std','pid'), &lt;br /&gt;
            'format'                  =&amp;gt; '&amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt;, %s (%s), %s %s %s - %s' &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier bastele ich mir die Ausgabezeile, mit dem Datum in fett, dann dem Ort, der Turnierart, Startgruppe und Klasse und der Info, ob Standard oder Lateinamerikanisch. Dann müsste dort eigentlich noch der Name des Tanzpaares hin, aber der steht ja nicht (direkt) in der Tabelle, sondern nur die ''pid''. Darum nehme ich erstmal die - besser als Nix. Ich vermute, ich muss/kann da mit einem Label-Callback arbeiten und die ''pid'' selbst in die Namen auflösen.&lt;br /&gt;
 &lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'global_operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'all' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['MSC']['all'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=select', &lt;br /&gt;
                'class'               =&amp;gt; 'header_edit_all', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ) &lt;br /&gt;
        ), &lt;br /&gt;
        'operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'edit' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['edit'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=edit', &lt;br /&gt;
                'icon'                =&amp;gt; 'edit.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'copy' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['copy'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=copy', &lt;br /&gt;
                'icon'                =&amp;gt; 'copy.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'delete' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['delete'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=delete', &lt;br /&gt;
                'icon'                =&amp;gt; 'delete.gif', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;if (!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\')) return false; Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ), &lt;br /&gt;
            'show' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['show'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=show', &lt;br /&gt;
                'icon'                =&amp;gt; 'show.gif' &lt;br /&gt;
            ) &lt;br /&gt;
        ) &lt;br /&gt;
    ),  					 &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier bleibt erstmal alles so, wie vom ''Extension-Creator'' vorgegeben.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '{couple_legend},pid;{tournament_legend},datum,turnierort,turnierart,startgruppe,startklasse,lat_std;' &lt;br /&gt;
                                    .'{result_legend},anzahlpaare,platz_von,platz_bis,bemerkung;' &lt;br /&gt;
    ), &lt;br /&gt;
    // Subpalettes &lt;br /&gt;
    'subpalettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        ''                            =&amp;gt; '' &lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
	 &lt;br /&gt;
Auch hier nichts spannendes: Eine normale Palette für alle Felder.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'pid' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['pid'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'foreignKey'              =&amp;gt; 'tl_gw_turnierpaare.partnernachname', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true) &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;		  &lt;br /&gt;
		  &lt;br /&gt;
''pid'' soll ein Foreign Key in die Turnierpaare-Tabelle sein. Mit der ''foreignKey''-Option wird das Dropdown-Feld mit den Partnernachnamen aus der Turnierpaar-Tabelle gefüllt. Zum ersten Testen ist das ganz OK, aber eigentlich stelle ich mir das anders vor: Es sollen dort nur AKTIVE Paare auswählbar sein, und ich hätte dort gerne die kompletten Namen des Turnierpaares stehen, nicht nur den Nachnamen des Herrn. Auch da wird wohl ein Callback hermüssen - später.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'datum' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['datum'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 11, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'datepicker'=&amp;gt;$this-&amp;gt;getDatePickerString(), 'tl_class'=&amp;gt;'w50 wizard', 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;64, 'rgxp' =&amp;gt; 'date') &lt;br /&gt;
        ), &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
		  &lt;br /&gt;
Abgeguckt beim DCA-Record für Artikel: Das Datumsfeld. Insbesondere den ''getDatePickerString()'' verstehe ich nicht - muss ich aber auch erstmal nicht. Kommt Zeit, kommt Erleuchtung.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'turnierort' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierort'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 1, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;128, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
		  &lt;br /&gt;
Nichts Besonderes hier...&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'turnierart' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierart'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'sorting'                 =&amp;gt; false, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$TurnierArten, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'includeBlankOption' =&amp;gt; true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
		  &lt;br /&gt;
Ähnlich wie bei den Startgruppen und Klassen lagere ich die Optionen für &amp;quot;Turnierart&amp;quot; in meine Frontendklasse aus. Gefällt mir besser so, und ich kann es &amp;quot;Re-usen&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'startgruppe' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['startgruppe'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 1, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$StartGruppen, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'includeBlankOption' =&amp;gt; true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'startklasse' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['startklasse'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'sorting'                 =&amp;gt; false, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$StartKlassen, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'lat_std' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['lat_std'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'sorting'                 =&amp;gt; false, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$TanzArten,&lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'tl_class' =&amp;gt; 'w&lt;br /&gt;
50') &lt;br /&gt;
        ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
		  &lt;br /&gt;
Wie zuvor, normale Dropdownfelder, deren Optionen ich in der Frontendklasse ''gwTurnierpaarliste'' ablege, um sie von verschiedenen Bereichen aus nutzen zu können.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'anzahlpaare' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['anzahlpaare'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;4, 'rgxp' =&amp;gt; 'digit') &lt;br /&gt;
        ), &lt;br /&gt;
        'platz_von' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_von'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;4, 'rgxp' =&amp;gt; 'digit', 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'platz_bis' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_bis'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;4, 'rgxp' =&amp;gt; 'digit', 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'bemerkung' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_meldungen']['bemerkung'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'textarea', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'cols' =&amp;gt; 80, 'rows' =&amp;gt; 20, 'allowHtml' =&amp;gt; false) &lt;br /&gt;
        ), &lt;br /&gt;
    ) &lt;br /&gt;
); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Auch hier eigentlich &amp;quot;Hausmannskost&amp;quot;: 3 Felder für Zahlen und ein Textfeld für die Bemerkung.&lt;br /&gt;
&lt;br /&gt;
''/system/modules/gw_turnierpaare/gwTurnierpaarliste.php'' (das Frontend-Modul) erweitere ich noch um die Optionenlisten für Tanzart und Turnierart:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  public static $TurnierArten = array('-', 'OT','ET', 'LM', 'DM', 'EM', 'WM'); &lt;br /&gt;
   &lt;br /&gt;
  public static $TanzArten = array('-', 'Std','Lat');&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum ersten Testen füge ich zwei Testdatensätze in die Meldungstabelle ein. Ergebnis:		&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_25.png]]&lt;br /&gt;
&lt;br /&gt;
Gut, die Tabellenheader sehen noch nicht so aus wie gewünscht, aber das ist Feinschliff. Die gewünschten Informationen (mit pid 7) werden angezeigt.&lt;br /&gt;
&lt;br /&gt;
Wenn ich einen neuen Eintrag hinzufüge, sieht das so aus:&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_26.png]]&lt;br /&gt;
&lt;br /&gt;
Durch das Fehlen der Language-Einträge natürlich noch sehr unschön, aber alle Felder sind da. Die Foreign-Key-Beziehung in die Turnierpaar-Tabelle klappt (rudimentär) auch.&lt;br /&gt;
&lt;br /&gt;
Mich wundert der &amp;quot;20.12.2000&amp;quot; als Default im Datumsfeld, aber ich habe auch keinen Default vorgegeben. Es wäre wohl praktisch, durch einen Load-Callback das aktuelle Datum dort als Default vorzugeben.&lt;br /&gt;
&lt;br /&gt;
Ich gebe also mal Daten ein:&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_27.png]]&lt;br /&gt;
&lt;br /&gt;
Und drücke auf Speichern- was sehe ich beim Datum:&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_28.png]]&lt;br /&gt;
&lt;br /&gt;
30.11.1999? Das habe ich im Datepicker aber nicht ausgewählt....auch eine manuelle Eingabe sorgt für das selbe 1999er-Ergebnis.&lt;br /&gt;
Und in der Übersichtstabelle dann das:&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_29.png]]&lt;br /&gt;
&lt;br /&gt;
0000-00-00...hm.&lt;br /&gt;
&lt;br /&gt;
Das ist alles nicht so ermutigend. Ich habe die Konfiguration für das Datumsfeld bei ''tl_article.php'' abgeschaut, da funktioniert ja auch alles.&lt;br /&gt;
&lt;br /&gt;
Bevor noch mehr Leute da Zeit reinstecken: Das Problem bei meinem Datumsfeld ist einfach, dass ich instinktiv in MYSQL ein ''date''-Feld angelegt habe. Es muss aber ein ''varchar(10)'' sein. Logisch ist das nicht. Also bitte keine weiteren Hinweise zur Fehlerbehebung, lindesbs war der Schnellste, danke :-).&lt;br /&gt;
&lt;br /&gt;
Hätte ich mehr Zeit gehabt, hätte ich mir selbst mal die DB-Struktur von ''tl_article'' angeschaut, um den Unterschied zu finden, Aber Zeit ist gerade knapp, und ich wollte endlich die nächste &amp;quot;Folge&amp;quot; rausschicken. Im nächsten Schritt wird das Datumsfeld also voraussichtlich hervorragend funktionieren, indem wir es in ein ''varchar(10)'' verwandeln :-).&lt;br /&gt;
&lt;br /&gt;
==Diskussion aus dem Forum==&lt;br /&gt;
{{Hinweis|Die Wiedergabe folgt dem Forums-Thread, der verschiedene Thematiken aufwirft. Sie muss daher noch umgearbeitet werden.}}&lt;br /&gt;
'''user: deerwood'''&lt;br /&gt;
 &lt;br /&gt;
Abgeguckt beim DCA-Record für Artikel: Das Datumsfeld. &lt;br /&gt;
Ich habe gerade mal schnell gecheckt: DB Datentyp DATE() wird in TL offenbar nirgendwo verwendet, alle Felder, die im DCA den DatePicker verwenden, haben in der DB den Datentyp VARCHAR(10) (bis auf tl_news.date, das ist merkwürdigerweise INT(10) ). Vielleicht ist das das Problem?&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
Ja, ich vermute sehr stark, dass das das Problem ist. Habe es einfach intuitiv (falsch) gemacht. Leider fehlte mir die Zeit, vorher &amp;quot;im Core&amp;quot; abzugucken. Eins habe ich sowieso schon gelernt: Das Einzige, auf was man sich in Sachen &amp;quot;TL-Entwickler-Doku&amp;quot; verlassen kann, ist der Core-Source ;-).&lt;br /&gt;
&lt;br /&gt;
EDIT: habe es schnell geändert und das Feld &amp;quot;datum&amp;quot; auf varchar(10) umgestellt. Jetzt klappt der Datepicker. Aber jetzt wird das Feld mit einem Unix-Timestamp gefüllt. Gebe ich das Feld also in meinen Tabellenzeilen aus oder als Sortierheader, steht dort nur Zahlenwust statt eines Datums. Ich wusste schon, warum ich lieber &amp;quot;date&amp;quot; haben wollte ;-). Ich kriege graue Haare. Da muss ich mir also definitiv noch was einfallen lassen...&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_30.png]]&lt;br /&gt;
&lt;br /&gt;
'''user: BugBuster''' &lt;br /&gt;
&lt;br /&gt;
der Timestamp hat aber den Vorteil, das du diesen einfach wandeln kannst, genauer in die Form die der Nutzer im Backend (Einstellungen / Startseite) definiert hat.&lt;br /&gt;
&lt;br /&gt;
Mein Modul hat z.B. solch eine Zeile:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$VisitorsStartDate = date($GLOBALS['TL_CONFIG']['dateFormat'],$objVisitors-&amp;gt;visitors_startdate);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$objVisitors-&amp;gt;visitors_startdate ist hier der Timestamp aus der DB.&lt;br /&gt;
 &lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
Sicherlich richtig, aber wenn ich per DCA-Record im Backend damit arbeiten will, z.b. als Sortier-, bzw. Gruppierfeld, dann habe ich nicht die Möglichkeit, dort ein &amp;quot;date()&amp;quot; zu injecten. Aber ich schaue mal weiter, was mit Callbacks geht und wie ich meiner Anforderung näherkomme. :-)&lt;br /&gt;
&lt;br /&gt;
'''TLight'''&lt;br /&gt;
 &lt;br /&gt;
Ich versuche nun, nach Deiner Vorlage eine Verwaltung für unseren Vereinsbekleidungs-Verleih zu programmieren. Ich habe den Extension-Creator, die Datenbank-Einrichtung und die DCA-Programmierung fürs Erste recht gut hinbekommen und alle kleinen Fehler ziemlich schnell lokalisieren und beheben können. Ich arbeite auf einer lokalen Installation und habe die Fehlermeldung eingeschaltet.&lt;br /&gt;
&lt;br /&gt;
Wenn ich mich richtig erinnere, so kommt seitdem ich das language file &amp;quot;modules.php&amp;quot; angefasst habe, &lt;br /&gt;
folgende Fehlermeldung:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Warning: Cannot modify header information - headers already sent by (output started at  &lt;br /&gt;
mein_pfad\system\modules\to_bekleidungsverleih\languages\de \modules.php:1) in  &lt;br /&gt;
mein_pfad\system\libraries\Template.php on line 174&lt;br /&gt;
#0 [internal function]: __error(2, 'Cannot modify h...', 'mein_pfad...', 174, Array)&lt;br /&gt;
#1 mein_pfad\system\libraries\Template.php(174): header('Content-Type: t...')&lt;br /&gt;
#2 mein_pfad\system\modules\backend\BackendTemplate.php(135): Template-&amp;gt;output()&lt;br /&gt;
#3 mein_pfad\typolight\main.php(286): BackendTemplate-&amp;gt;output()&lt;br /&gt;
#4 mein_pfad\typolight\main.php(102): Main-&amp;gt;output()&lt;br /&gt;
#5 mein_pfad\typolight\main.php(295): Main-&amp;gt;run()&lt;br /&gt;
#6 {main} &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Leider bin ich nun mit meinem Latein am Ende... Weiß jemand Rat? &lt;br /&gt;
&lt;br /&gt;
'''user: Toflar'''&lt;br /&gt;
 &lt;br /&gt;
Bei Dir ist irgend ein Zeichen vor der ersten php Anweisung   Also wahrscheinlich &amp;quot; &amp;lt;?php&amp;quot; statt &amp;quot;&amp;lt;?php&amp;quot; oder sowas &lt;br /&gt;
  &lt;br /&gt;
'''user: TLight''' &lt;br /&gt;
&lt;br /&gt;
Ich habe in modules.php nachgesehen - leider ist dort kein Freizeichen. Auch in keiner anderen der von mir angefassten Dateien (soweit ich mich erinnern kann). Zu allem Überfluss bemerke ich gerade, dass beim Laden der Startseite des Backends folgender Fehler 2x vor dem o. g. Fehler gelistet wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Warning: Illegal offset type in mein_pfad\typolight\main.php on line 183&lt;br /&gt;
#0 mein_pfad\typolight\main.php(183): __error(2, 'Illegal offset ...', 'mein_pfad...', 183, Array)&lt;br /&gt;
#1 mein_pfad\typolight\main.php(93): Main-&amp;gt;welcomeScreen()&lt;br /&gt;
#2 mein_pfad\typolight\main.php(295): Main-&amp;gt;run()&lt;br /&gt;
#3 {main} &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''user: xchs''' &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 Zitat von TLight   &lt;br /&gt;
...leider ist dort kein Freizeichen. Auch in keiner anderen der von mir angefassten Dateien (soweit ich mich  &lt;br /&gt;
erinnern kann).&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das kann aber unter Umständen auch ein verstecktes Zeichen sein, je nachdem welchen Editor Du verwendest (UTF-8 vs. UTF-8 BOM usw.)&lt;br /&gt;
&lt;br /&gt;
'''user: TLight''' &lt;br /&gt;
&lt;br /&gt;
Nein, leider nichts zu finden. Auch im stinknormalen Editor ist da kein Zeichen. Ich verwende UTF-8-Codierung, aber auch da konnte ich nichts finden...&lt;br /&gt;
   &lt;br /&gt;
'''user: FloB''' &lt;br /&gt;
&lt;br /&gt;
Schau alle Dateien durch. Mit welchem Editor bearbeitest du die Dateien? Schau mal da nach eine Option bezüglich des BOM. Einen BOM &amp;quot;siehst&amp;quot; du eigentlich auch nur in einem Hex-Editor.&lt;br /&gt;
 &lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
Hmm, es muss aber definitiv was mit modules.php, Zeile 1 zu tun haben.&lt;br /&gt;
Wenn du magst, kannst du mir dein File schicken (zip, damit beim Versenden nix passiert), per Private Mail.&lt;br /&gt;
&lt;br /&gt;
'''user: Jürgen''' &lt;br /&gt;
&lt;br /&gt;
Ich hatte heute auch das Problem mit diesem Fehler. Wollte zwei Ankreuzfelder ergänzen. Hab dann die Codierung von UTF-8 auf UTF-8 ohne BOM umgestellt und siehe, da seit dem klappt es. Benutze das Notepad++ unter Windows.&lt;br /&gt;
&lt;br /&gt;
Wenn ich noch eine Frage stellen darf. Wenn ich calender_events um zwei Checkboxen erweitern möchte und das der Titel_legende zuweise wird ein Checkboxfeld verdoppelt und die Legende verschwindet. Erweitere ich aber z.B. die Publish_legende werden wie gewünscht nur zwei Felder angezeigt und auch die Legende bleibt erhalten.&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely'''&lt;br /&gt;
 &lt;br /&gt;
Schick mir mal bitte deine /lang/de/modules.php Sprachdatei (Oder zeige sie uns hier, die ist ja nicht so lang).&lt;br /&gt;
 &lt;br /&gt;
Ich weiß ja nicht, ob du es genauso wie ich gemacht hast, aber ich bin über diesen Fehler auch gestolpert, aber das gehört zum nächsten Teil des Tagebuchs. Und bevor wir hier in die falsche Richtung rennen, würde ich gerne sehen, wie diese Datei aussieht. Falls es &amp;quot;mein&amp;quot; Fehler ist, kann ich dir dann sagen woran es liegt ;-).&lt;br /&gt;
&lt;br /&gt;
Oder um es doch hier vorweg zu nehmen: Wenn du wie ich in der aktuellen Version dein(e) Backendmodul(e) unter eine eigene Obergruppe gesetzt hast (bei mir ''gw_paarverwaltung''), dann darf der entsprechende Übersetzungseintrag $GLOBALS['TL_LANG']['MOD']['gw_paarverwaltung'] NICHT ein Array sein (erster Eintrag Text fürs Menü, zweiter Eintrag der Erklärungstext), sondern einfach nur ein String, der den Menüeintrag darstellt. Das ist anders als bei den Einträgen für die Module selbst. Bei meinem Modul ist das jetzt so:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Back end modules &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['gw_turnierpaare'] = array('Turnierpaare', 'Verwaltung der Turnierpaare.'); &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['gw_meldungen'] = array('Meldungen', 'Verwaltung der Turniermeldungen (Meldeliste).'); &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['gw_paarverwaltung'] = 'Paarverwaltung';  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die letzte Zeil ist der Menüeintrag für die &amp;quot;Gruppe&amp;quot; im Backendmenü, die ersten beiden Einträge die Werte für meine beiden Backendmodule. Hatte auch für die &amp;quot;Gruppe&amp;quot; ein Array aus Menütext und Erklärungstext, und das brachte mir den von dir beschriebenen Fehler. Ist das dein Problem? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely'''&lt;br /&gt;
&lt;br /&gt;
Mal ein Schuss ins Blaue: Macht dein str_replace für den Paletteneintrag wirklich das richtige? Check das lieber mal durch ein Debugging-Echo oder ähnlich. Beim richtigen str_replace() zur Modifikation der bestehenden Palette kann man sich böse vertun.&lt;br /&gt;
&lt;br /&gt;
OK, hier Kommando zurück. Der von mir beschriebene Fehler kann erst zuschlagen, wenn man eine Modifikation der ''/config/config.php'' macht, die ich bisher hier noch gar nicht beschrieben habe, sondern die erst in der nächsten Tagebuchfolge erscheint. Wenn du also bisher alles so gemacht hast wie ich, kann es nicht dein Problem sein. Trotzdem hat das Problem definitiv mit falschen Einträgen in den Language-Dateien (und zwar ''modules.php'') zu suchen. Entweder hast du irgendwo ein Array, wo ein String erwartet wird, oder umgekehrt.&lt;br /&gt;
&lt;br /&gt;
Falls du es selbst nicht findest, bitte deine ''config/config.php'' und ''language/de/modules.php'' zu mir, dann schaue ich mir das an.&lt;br /&gt;
&lt;br /&gt;
Sorry für die Verwirrung, das ist das Problem, wenn der eigentliche Code schon einen Schritt weiter ist als die aktuelle Tagebuchberichterstattung...&lt;br /&gt;
&lt;br /&gt;
'''user: TLight''' &lt;br /&gt;
&lt;br /&gt;
@dl1ely: wahrscheinlich habe ich genau den von Dir beschriebenen Fehler gemacht!&lt;br /&gt;
''/config/config.php'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$GLOBALS['BE_MOD']['to_bekleidungsverleih']['to_magazin'] = array &lt;br /&gt;
( &lt;br /&gt;
    'tables' =&amp;gt; array('tl_to_bkvs_magazin'), &lt;br /&gt;
    'icon'   =&amp;gt; 'system/modules/to_bekleidungsverleih/icons/trikot.png' &lt;br /&gt;
);  &lt;br /&gt;
$GLOBALS['BE_MOD']['to_bekleidungsverleih']['to_verleih'] = array &lt;br /&gt;
( &lt;br /&gt;
    'tables' =&amp;gt; array('tl_to_bkvs_verleih'), &lt;br /&gt;
    'icon'   =&amp;gt; 'system/modules/to_bekleidungsverleih/icons/trikot.png' &lt;br /&gt;
);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''/languages/de/modules.php'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Back end modules &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['to_bekleidungsverleih'] = array('Bekleidungsverleih', ''); &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['to_magazin']            = array('Magazin', ''); &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['to_verleih']            = array('Verleih', '');  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Leider habe ich Deine Lösung nicht ganz verstanden. Aber ich warte einfach auf Deinen neuen Tagebucheintrag. Will Dir nicht noch mehr Arbeit machen als Du eh schon hast.&lt;br /&gt;
&lt;br /&gt;
Wenn ich die ''/languages/de/modules'' wie folgt ändere:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Back end modules &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['to_bekleidungsverleih'] ='Bekleidungsverleih'; &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['to_magazin']            = array('Magazin', ''); &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['to_verleih']            = array('Verleih', '');&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
verschwinden zwar die zwei Fehler der Startseite und das Modul wird in der Mittelspalte angezeigt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Warning: Illegal offset type in mein_pfad\typolight\main.php on line 183&lt;br /&gt;
#0 mein_pfad\typolight\main.php(183): __error(2, 'Illegal offset ...', 'mein_pfad...', 183, Array)&lt;br /&gt;
#1 mein_pfad\typolight\main.php(93): Main-&amp;gt;welcomeScreen()&lt;br /&gt;
#2 mein_pfad\typolight\main.php(295): Main-&amp;gt;run()&lt;br /&gt;
#3 {main}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Der Ursprungsfehler bleibt aber:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Warning: Cannot modify header information - headers already sent by (output started at  &lt;br /&gt;
mein_pfad\system\modules\to_bekleidungsverleih\lan guages\de \modules.php:1) in  &lt;br /&gt;
mein_pfad\system\libraries\Template.php on line 174&lt;br /&gt;
#0 [internal function]: __error(2, 'Cannot modify h...', 'mein_pfad...', 174, Array)&lt;br /&gt;
#1 mein_pfad\system\libraries\Template.php(174): header('Content-Type: t...')&lt;br /&gt;
#2 mein_pfad\system\modules\backend\BackendTemplate.p hp(135): Template-&amp;gt;output()&lt;br /&gt;
#3 mein_pfad\typolight\main.php(286): BackendTemplate-&amp;gt;output()&lt;br /&gt;
#4 mein_pfad\typolight\main.php(102): Main-&amp;gt;output()&lt;br /&gt;
#5 mein_pfad\typolight\main.php(295): Main-&amp;gt;run()&lt;br /&gt;
#6 {main}&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
 Angehängte Dateien &lt;br /&gt;
o  bekleidung.zip (5,9 KB, 3x aufgerufen)&lt;br /&gt;
 &lt;br /&gt;
--&amp;gt; gelöst!!! &lt;br /&gt;
Bevor sich nun zu viele mit meinem Problem beschäftigen, hier die Lösung:&lt;br /&gt;
&lt;br /&gt;
Habe meine Dateien in Notepad++ in UTF-8 ohne BOM konvertiert - und das Problem hat sich erledigt. Was &lt;br /&gt;
zum T. ist BOM? Nun ja, vielen Dank für all Eure Hilfe. Toll, wie schnell das geklappt hat!  &lt;br /&gt;
&lt;br /&gt;
'''user: Jürgen''' &lt;br /&gt;
&lt;br /&gt;
 Zitat von dl1ely   &lt;br /&gt;
Mal ein Schuss ins Blaue: Macht dein str_replace für den Paletteneintrag wirklich das richtige? Check das lieber  &lt;br /&gt;
mal durch ein Debugging-Echo oder ähnlich. Beim richtigen str_replace() zur Modifikation der bestehenden  &lt;br /&gt;
Palette kann man sich böse vertun.&lt;br /&gt;
Stefan&lt;br /&gt;
 Zitat von TLight   &lt;br /&gt;
Bevor sich nun zu viele mit meinem Problem beschäftigen, hier die Lösung:&lt;br /&gt;
Habe meine Dateien in Notepad++ in UTF-8 ohne BOM konvertiert - und das Problem hat sich erledigt. Was  &lt;br /&gt;
zum T. ist BOM? Nun ja, vielen Dank für all Eure Hilfe. Toll, wie schnell das geklappt hat!  &lt;br /&gt;
Gruß, Torsten&lt;br /&gt;
@Torsten: Gerne. Ich war auch schon kurz vor dem verzweifeln mit dem BOM.&lt;br /&gt;
@Stefan: Ich hab das Beispiel &amp;quot;CalenderFreeEntry&amp;quot; aus dem Wiki benutzt. Auch dort tritt das Problem auf. Genauer gesagt wird beim Hinzufügen von einer Checkbox die Legende nicht mehr angezeigt (nur bei Titel_legende). Wenn ich nun eine zweite Checkbox hinzufüge erscheint eine von diesen doppelt. Sobald ich es auf eine andere Legende lege funktioniert alles wie erwartet.&lt;br /&gt;
    &lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
Naja, &amp;quot;Lösung nicht verstanden&amp;quot;. Eine Lösung ist es eigentlich nicht, eher eine Erklärung.&lt;br /&gt;
to_bekleidungsverleih ist die &amp;quot;Obergruppe&amp;quot; im Backend-Modul-Menü für deine beiden Backend-Module to_magazin und to_verleih. Und bei TL ist es nunmal so, dass dann in der Language-Datei bei der Obergruppe nur ein einzelner Übersetzungsstring stehen darf, während bei den Backendmodulen selbst ein Array bestehend aus Übersetzung des Menüeintrags und des Erklärungstextes stehen muss.&lt;br /&gt;
Witzigerweise bist du in genau dasselbe Problem wie ich gelaufen, aber ich hätte erst in der nächsten Tagebuchausgabe davon berichtet. Jetzt ist ja alles geklärt.&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
 Zitat von Jürgen   &lt;br /&gt;
@Stefan: Ich hab das Beispiel [http://dev.contao.org/wiki/1/TutorialsVorhandeneModuleErweitern1 CalenderFreeEntry] aus dem Wiki benutzt. Auch dort tritt das Problem auf.  &lt;br /&gt;
Genauer gesagt wird beim Hinzufügen von einer Checkbox die Legende nicht mehr angezeigt (nur bei Titel_legende). Wenn ich nun eine zweite Checkbox hinzufüge erscheint eine von diesen doppelt. Sobald ich es auf eine andere Legende lege funktioniert alles wie erwartet. Das versteh ich nicht.  &lt;br /&gt;
&lt;br /&gt;
Wenn es bei allen Legenden funktioniert und bei der Titel_legende nicht. Vielleicht liegt es daran das Titel_legende die erste beim Calendar_event ist?&lt;br /&gt;
&lt;br /&gt;
Wie gesagt, der einzige Tip, den ich erstmal habe, wäre per echo o.ä. sich den String der Palettendefinition im DCA nach der Modifikation anzugucken. Ich vermute einfach, da läuft beim str_replace oder wie auch immer der bestehende String modifziert wird was schief. Ohne den String zu sehen ist das aber schwer zu sagen...&lt;br /&gt;
&lt;br /&gt;
'''user: FloB''' &lt;br /&gt;
&lt;br /&gt;
 Zitat von TLight   &lt;br /&gt;
Was zum T. ist BOM?&lt;br /&gt;
&lt;br /&gt;
[[w:de:Byte_Order_Mark|Byte Order Mark]] &lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
 Zitat von FloB   &lt;br /&gt;
http://de.wikipedia.org/wiki/Byte_Order_Mark&lt;br /&gt;
Übrigens, aus meiner persönlichen Sicht ist die mangelnde Kenntnis dieser Abkürzung keine Schande - ich kannte sie bis vor Kurzem auch noch nicht und habe sie erst in der Wikipedia kennengelernt. Und das obwohl ich mir eigentlich einbilde, in der Informatik-Welt schon umfangreiche Kenntnisse zu besitzen. Bei UTF habe ich aber wohl noch Lücken ;-)&lt;br /&gt;
&lt;br /&gt;
'''user: klabog''' &lt;br /&gt;
&lt;br /&gt;
Am Schluss sollte dabei allerdings ein HowTo herauskommen, das die Entwicklung Schritt für Schritt abbildet und auf die möglichen Fehler an entsprechender Stelle hinweist.&lt;br /&gt;
&lt;br /&gt;
Das muss nicht notwendigerweise von Dir kommen, Du machst Dir schon genug Arbeit, sondern vielleicht von einem Team das Deine Vorlage redaktionell bearbeitet und zusammen mit Dir vielleicht eine Extension bastelt die vom speziellen Fall auf eine universelle Variante zielt.&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
Naja gut, schauen wir mal...Vielleicht kann man das in der Tat &amp;quot;am Ende&amp;quot; in ein &amp;quot;normales&amp;quot;, leichter lesbares Tutorial umwandeln. Leider geht es momentan nicht voran, weil ich meine Prioritäten außerhalb von TL leider höher setzen muss. Der Tag hat nur 24 Stunden, und ich brauche momentan auch ohne das Tagebuch gefühlt mindestens 48h.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_meldeliste.png</id>
		<title>Datei:Gw meldeliste.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_meldeliste.png"/>
				<updated>2010-07-07T20:48:36Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-11 Backend Zweite Tabelle&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-11 Backend Zweite Tabelle&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-10_Frontend_Feinschliff</id>
		<title>TEE-10 Frontend Feinschliff</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-10_Frontend_Feinschliff"/>
				<updated>2010-07-07T20:11:40Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Etwas…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Etwas Feinschliff=&lt;br /&gt;
Einige Details will ich noch verbessern, bevor es endlich an die noch fehlenden Turniermeldungen geht.&lt;br /&gt;
&lt;br /&gt;
Insgesamt ist es ein Mischmasch von vielen Kleinigkeiten, die aber teilweise in mehreren Dateien Auswirkungen haben. Es könnte also chaotisch werden :-).&lt;br /&gt;
&lt;br /&gt;
Beginnen wir wir mit ''/system/modules/gw_turnierpaare/geTurnierpaarliste.php'', der Klasse in der die Frontendtemplates gefüllt werden.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class gwTurnierpaarliste extends Module &lt;br /&gt;
{ &lt;br /&gt;
    /** &lt;br /&gt;
     * Template &lt;br /&gt;
     * @var string &lt;br /&gt;
     */ &lt;br /&gt;
    protected $strTemplate = 'gw_turnierpaarliste'; &lt;br /&gt;
    protected $strDetailTemplate = 'gw_turnierpaarliste_detail'; &lt;br /&gt;
    protected $strDetailErrorTemplate = 'gw_turnierpaarliste_error'; &lt;br /&gt;
  public static $strDetailKey = 'info'; &lt;br /&gt;
   &lt;br /&gt;
  public static $StartGruppen = array('KIN I','KIN II', 'JUN I', 'JUN II', 'JUG', 'HGR', 'HGR II', 'SEN I', 'SEN II', 'SEN III', 'SEN IV'); &lt;br /&gt;
   &lt;br /&gt;
  public static $StartKlassen = array('-', 'E','D', 'C', 'B', 'A', 'S', 'PRO', 'LL', 'OL', 'RL', '2. BL', '1. BL');  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zunächst definiere ich mir neben meinem &amp;quot;Defaulttemplate&amp;quot; noch einen Templatenamen für die Detailansicht, und ein &amp;quot;Error-Template&amp;quot;, das angezeigt wird, wenn das für die Detailansicht gewünschte Tanzpaar nicht gefunden wird.&lt;br /&gt;
&lt;br /&gt;
Dann folgen 3 statische Variablendeklarationen, dies sind also Klassenvariablen. Die werde ich Klassenübergreifend nutzen, weil die entsprechenden Einträge in mehreren Files genutzt werden, und ich sie nur an einer Stelle editieren möchte. ''$strDetailKey'' benötigen wir im Listentemplate, die beiden anderen Variablen im DCA-Record für die Tabelle ''tl_gw_turnierpaare'' und für die sortierte Ausgabe nach Startgruppe und -klasse.&lt;br /&gt;
&lt;br /&gt;
Hier verwenden wir sie dann auch (Funktion ''compileListTemplate()''):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
... &lt;br /&gt;
      // Nach Altersgruppen sortieren &lt;br /&gt;
      $fieldstartgruppe=&amp;quot;''&amp;quot;; &lt;br /&gt;
       foreach(gwTurnierpaarliste::$StartGruppen as $gruppe) &lt;br /&gt;
      { &lt;br /&gt;
        $fieldstartgruppe .= &amp;quot;,'&amp;quot;.$gruppe.&amp;quot;'&amp;quot;; &lt;br /&gt;
      } &lt;br /&gt;
      $fieldstartklasse=&amp;quot;''&amp;quot;; &lt;br /&gt;
      foreach(gwTurnierpaarliste::$StartKlassen as $klasse) &lt;br /&gt;
      {&lt;br /&gt;
        $fieldstartklasse .= &amp;quot;,'&amp;quot;.$klasse.&amp;quot;'&amp;quot;; &lt;br /&gt;
      } &lt;br /&gt;
...  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und auch die Verwendung von ''$strDetailKey'' wird angepasst:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
... &lt;br /&gt;
        if ( strlen($this-&amp;gt;Input-&amp;gt;get(gwTurnierpaarliste::$strDetailKey)) ) &lt;br /&gt;
...  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im DCA-Record für die Felder ''startgruppe'', ''startklasselatein'' und ''startklassestandard'' sinngemäß (Datei  ''/system/modules/gw_turnierpaare/dca/tl_gw_turnierpaare.php''):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
... &lt;br /&gt;
        'startgruppe' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startgruppe'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$StartGruppen, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'includeBlankOption' =&amp;gt; true) &lt;br /&gt;
        ), &lt;br /&gt;
        'startklasselatein' =&amp;gt; array &lt;br /&gt;
        (&lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklasselatein'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$StartKlassen, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'startklassestandard' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklassestandard'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'options'                 =&amp;gt; gwTurnierpaarliste::$StartKlassen, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true) &lt;br /&gt;
        ), &lt;br /&gt;
...&lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
und schließlich noch im Template für die Übersichtsliste ''/system/modules/gw_turnierpaare/templates/gw_turnierpaarliste.tpl'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
... &lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;?php echo '&amp;lt;a href=&amp;quot;/{{env::page_alias}}/'.gwTurnierpaarliste::&lt;br /&gt;
$strDetailKey.'/'.$paar['alias'].'.html&amp;quot;&amp;gt;Detail&amp;lt;/a&amp;gt;'; ?&amp;gt; &lt;br /&gt;
... &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier benutzen wir auch das Insert-Tag ''{{env:  age_alias}}'', um den Seitenalias nicht wie bisher hart im Template kodiert zu haben. Das funktioniert jetzt, egal wie die Seite heißt, auf der das Frondendmodul eingebunden wird.&lt;br /&gt;
&lt;br /&gt;
Hier sieht man auch noch eine andere Änderung: ''$paar['alias']''. Ich möchte die Detailseite nicht nur über die numerische ID des Paares aufrufen können, sondern eleganter über einen Seitenalias, z.b. /turnierpaarliste/info/mueller.html.&lt;br /&gt;
&lt;br /&gt;
Dafür definiere ich ein neues ''varchar(128)''-Feld in der ''tl_gw_turnierpaare-Tabelle'' (''/system/modules/gw_turnierpaare/config/database.sql''):&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
  `partnerinvorname` varchar(64) NULL default NULL,&lt;br /&gt;
  `alias` varchar(128) NOT NULL default '',&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '',&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Definitionen für den DCA-Record klaue ich mir bei ''tl_article.php'' aus dem Backend (''/system/modules/gw_turnierpaare/dca/tl_gw_turnierpaare.php''):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
... &lt;br /&gt;
        'alias' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']&lt;br /&gt;
['tl_gw_turnierpaare']['alias'], &lt;br /&gt;
            'exclude'                 =&amp;gt; true, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('rgxp'=&amp;gt;'alnum', 'doNotCopy'=&amp;gt;true, 'spaceToUnderscore'=&amp;gt;true, 'maxlength'=&amp;gt;128, 'tl_class'=&amp;gt;'w50'), &lt;br /&gt;
            'save_callback' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                array('tl_gw_turnierpaare', 'generateAlias') &lt;br /&gt;
            ) &lt;br /&gt;
    ), &lt;br /&gt;
... &lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
In die Palette tragen wir das Feld auch noch ein, damit es manuell editierbar bleibt:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array('resetpassword'), &lt;br /&gt;
        'default'                     =&amp;gt; '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname,alias;' &lt;br /&gt;
                                      .'{classes_legend},startgruppe,startklasselatein,startklassestandard;' &lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
Und wir müssen den Callback schreiben&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  /** &lt;br /&gt;
   * Generate alias from couples names &lt;br /&gt;
   */ &lt;br /&gt;
    public function generateAlias($varValue, DataContainer $dc) &lt;br /&gt;
    { &lt;br /&gt;
        $autoAlias = false; &lt;br /&gt;
        // Generate alias if there is none &lt;br /&gt;
        if (!strlen($varValue)) &lt;br /&gt;
        { &lt;br /&gt;
            $autoAlias = true; &lt;br /&gt;
            $key = $dc-&amp;gt;activeRecord-&amp;gt;partnernachname; &lt;br /&gt;
            if(strlen($dc-&amp;gt;activeRecord-&amp;gt;partnerinnachname) &amp;gt; 0 &amp;amp;&amp;amp; strcmp($dc-&amp;gt;activeRecord-&amp;gt;partnernachname,$dc-&amp;gt;activeRecord-&amp;gt;partnerinnachname)) &lt;br /&gt;
            { &lt;br /&gt;
        $key = $key.'_'.$dc-&amp;gt;activeRecord-&amp;gt;partnerinnachname; &lt;br /&gt;
      } &lt;br /&gt;
            $varValue = standardize($key); &lt;br /&gt;
        } &lt;br /&gt;
        $objAlias = $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;SELECT id FROM tl_gw_turnierpaare WHERE id=? OR alias=?&amp;quot;) &lt;br /&gt;
                                   -&amp;gt;execute($dc-&amp;gt;id, $varValue); &lt;br /&gt;
        // Check whether the page alias exists &lt;br /&gt;
        if ($objAlias-&amp;gt;numRows &amp;gt; 1) &lt;br /&gt;
        { &lt;br /&gt;
            if (!$autoAlias) &lt;br /&gt;
            { &lt;br /&gt;
                throw new Exception(sprintf($GLOBALS['TL_LANG']['ERR']['aliasExists'], $varValue)); &lt;br /&gt;
            } &lt;br /&gt;
            $varValue .= '-' . $dc-&amp;gt;id; &lt;br /&gt;
        } &lt;br /&gt;
        return $varValue; &lt;br /&gt;
    } &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
	 &lt;br /&gt;
Der Seitenalias ist ''nachnameherr_nachnamedame'', wenn die Nachnamen verschieden sind, falls sie gleich sind nur ''nachname''. Ein Paar Müller/Schulze wäre also mueller_schulze, ein Ehepaar Maier nur maier. Das ganze wird mit einer eingebauten TL-Funktion standardisiert. Sollte der Alias schon existieren (eher unwahrscheinlich), dann wird die ID hintenan gehängt. Das ist 1:1 so wie bei Seitenaliasen in TL auch.&lt;br /&gt;
&lt;br /&gt;
Im Frontendmodul ''/system/modules/gw_turnierpaare/gwTurnierpaarliste.php'' erfolgen dafür nun auch noch Anpassungen. Zunächst in der Funktion ''obj2Arr'', damit das neue Feld auch im Template zur Verfügung steht:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
... &lt;br /&gt;
        'id' =&amp;gt; $objPaar-&amp;gt;id, &lt;br /&gt;
        'alias' =&amp;gt; $objPaar-&amp;gt;alias, &lt;br /&gt;
        'beschreibung' =&amp;gt; $objPaar-&amp;gt;beschreibung, &lt;br /&gt;
...  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
und schließlich in ''compileDetailTemplate'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // Compiles the data for the turnierparliste_detail template &lt;br /&gt;
  protected function compileDetailTemplate() &lt;br /&gt;
  { &lt;br /&gt;
    $coupleRow = $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;SELECT * FROM tl_gw_turnierpaare WHERE id=? OR alias=?&amp;quot;) 		  &lt;br /&gt;
            -&amp;gt;limit(1) &lt;br /&gt;
            -&amp;gt;execute($this-&amp;gt;Input-&amp;gt;get(self::$strDetailKey),$this-&amp;gt;Input-&amp;gt;get(self::$strDetailKey)); &lt;br /&gt;
    if($coupleRow-&amp;gt;numRows == 0) &lt;br /&gt;
    { &lt;br /&gt;
          $this-&amp;gt;Template = new FrontendTemplate($this-&amp;gt;strDetailErrorTemplate); &lt;br /&gt;
    } &lt;br /&gt;
    else &lt;br /&gt;
    { &lt;br /&gt;
      $this-&amp;gt;Template = new FrontendTemplate($this-&amp;gt;strDetailTemplate); &lt;br /&gt;
      $newArr = $this-&amp;gt;obj2Arr($coupleRow); &lt;br /&gt;
      if(strlen($coupleRow-&amp;gt;bild) == 0) &lt;br /&gt;
      { &lt;br /&gt;
        $newArr['bild'] = '/system/modules/gw_turnierpaare/icons/default.png'; &lt;br /&gt;
      } &lt;br /&gt;
      else &lt;br /&gt;
      { &lt;br /&gt;
        $newArr['bild'] = $this-&amp;gt;getImage($coupleRow-&amp;gt;bild, '180', ''); &lt;br /&gt;
        $newArr['bildfullsize'] = $coupleRow-&amp;gt;bild; &lt;br /&gt;
      } &lt;br /&gt;
      $this-&amp;gt;Template-&amp;gt;paar = $newArr; &lt;br /&gt;
    } &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
Hier wird entweder nach ID oder nach Alias gesucht. Aufruf der Detailseite würde also sowohl über /info/12.html als auch info/mueller.html funktionieren. Wird kein Datensatz mit dieser ID gefunden, wird das Error-Template ausgegeben, ansonsten wie üblich der Detail-Datensatz.&lt;br /&gt;
&lt;br /&gt;
Schließlich noch das sehr simple neue Template 	''system/modules/gw_turnierpaare/templates/gw_turnierpaarliste_error.tpl'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;&amp;lt;?php echo $this-&amp;gt;class; ?&amp;gt; block paarvisitenkarte&amp;quot;&amp;lt;?php echo $this-&amp;gt;cssID; ?&amp;gt; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;style): ?&amp;gt; style=&amp;quot;&amp;lt;?php echo $this-&amp;gt;style; ?&amp;gt;&amp;quot;&amp;lt;?php endif; ?&amp;gt;&amp;gt; &lt;br /&gt;
&amp;lt;h3&amp;gt;Dieses Paar existiert leider nicht!&amp;lt;/h3&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da sich rein optisch außer einem Extra Feld im Backend für den Alias nichts getan hat, verzichte ich in diesem Schritt auf Screenshots. Leider ging es auch etwas kreuz und quer mit kleinen Änderungen in mehreren Dateien. Ich hoffe trotzdem man konnte noch folgen... &lt;br /&gt;
&lt;br /&gt;
==Diskussion==&lt;br /&gt;
'''user: Jürgen''' &lt;br /&gt;
&lt;br /&gt;
Eine Frage zu der Demoanwendung am Anfang. Diese habe ich installiert und das Backend funktioniert auch &lt;br /&gt;
gut. Nur das erstellen eines Moduls macht mir Schwierigkeiten. Da scheint Typolight sich aufzuhängen. Der &lt;br /&gt;
Bildschirm bleibt einfach weiß.&lt;br /&gt;
&lt;br /&gt;
Ich hab es local unter winxp pro oder win7 pro unter xampp laufen. Ich hab mal ''displayErrors'' aktiviert und als &lt;br /&gt;
erstes kommt die Fehlermeldung&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Warning: Cannot modify header information - headers already sent by (output started at  &lt;br /&gt;
G:\xampplite\htdocs\test\system\modules\gw_turnier paare\dca\tl_module.php:32) in  &lt;br /&gt;
G:\xampplite\htdocs\test\system\libraries\Template .php on line 174 &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
bitte öffne ''/system/modules/gw_turnierpaare/dca/tl_module.php'' in einem Editor. Zeilen 31 und 32 sind &lt;br /&gt;
Leerzeilen, bitte entferne die. Die letzte Zeile muss Zeile 30 mit &amp;quot;?&amp;gt;&amp;quot; sein.&lt;br /&gt;
&lt;br /&gt;
Ich denke, daran wird es liegen. Ich vermute, das hängt mit den unterschiedlichen Zeilenumbrüchen bei &lt;br /&gt;
Linux/Windows zusammen, bei mir tritt das Problem zumindest nicht auf. Dadurch werden wohl zwei Leerzeilen &lt;br /&gt;
ausgegeben, bevor dann in Zeile 174 von ''system/libraries/Template.php'' der Header für die Seite gesetzt wird. &lt;br /&gt;
Das schlägt dann natürlich fehl. In Zukunft werde ich mehr auf die Leerzeilen-Problematik achten. In der &lt;br /&gt;
nächsten &amp;quot;Version&amp;quot; des Quelltexts wird das behoben sein.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-09_Frontend_Detailliste</id>
		<title>TEE-09 Frontend Detailliste</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-09_Frontend_Detailliste"/>
				<updated>2010-07-07T20:04:59Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Detai…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Details, Details, Details=&lt;br /&gt;
In der Listenübersicht der Turnierpaare ist als Link bereits vorgesehen, dass man beim Klick auf den &amp;quot;Detail&amp;quot;-Link eines Paares zu einer Detail-Seite kommen kann. Ich möchte das mit demselben Modul regeln, also ohne Weiterleitungsseite auf eine (versteckte) Seite mit einem &amp;quot;DetailViewer&amp;quot;-Modul.&lt;br /&gt;
&lt;br /&gt;
Ich habe mir das schamlos beim EFG abgeguckt. Meine Turnierpaarliste liegt unter ''turnierpaarliste.html''. Wenn man als URL z.B. turnierpaarliste/info/8.html verwendet, wird trotzdem die Seite ''turnierpaarliste'' aufgerufen, aber jetzt hat der GET-Parameter &amp;quot;info&amp;quot; den Wert 8. Sehr praktisch.&lt;br /&gt;
&lt;br /&gt;
Prüft man im Modulcode auf diesen Parameter, kann man dann gegebenenfalls auf das Detail-Template wechseln und anderen Code ausführen.&lt;br /&gt;
&lt;br /&gt;
Nochmal der entsprechende Abschnitt aus dem Template der ''/system/modules/gw_turnierpaare/templates/gw_turnierpaarliste.tpl'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;/td&amp;gt; &lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;?php echo '&amp;lt;a href=&amp;quot;/turnierpaarliste/info/'.$paar['id'].'.html&amp;quot;&amp;gt;Detail&amp;lt;/a&amp;gt;'; ?&amp;gt; &lt;br /&gt;
  &amp;lt;/td&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
 &lt;br /&gt;
Hier wird aus der Paar-ID der Detail-Link gebaut. Mich stört noch, dass mein Seitenname &amp;quot;turnierpaarliste&amp;quot; hardkodiert ist. Das werde ich noch ändern müssen, habe gerade aber keine Idee, wie ich an diese Information komme. Außerdem wäre es schöner, statt mit der numerischen ID mit einem alphanumerischen Alias zu arbeiten, so wie bei Seiten oder Artikeln. Das werde ich noch in einem zukünftigen Schritt implementieren.&lt;br /&gt;
&lt;br /&gt;
Das Template für die Detailseite ''/system/modules/gw_turnierpaare/templates/gw_turnierpaarliste_detail.tpl'' sieht so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;&amp;lt;?php echo $this-&amp;gt;class; ?&amp;gt; block paarvisitenkarte&amp;quot;&amp;lt;?php echo $this-&amp;gt;cssID; ?&amp;gt; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;style): ?&amp;gt; style=&amp;quot;&amp;lt;?php echo $this-&amp;gt;style; ?&amp;gt;&amp;quot;&amp;lt;?php endif; ?&amp;gt;&amp;gt; &lt;br /&gt;
&amp;lt;h3&amp;gt;&amp;lt;?php echo $this-&amp;gt;paar['partnernachname']; ?&amp;gt; &lt;br /&gt;
&amp;lt;?php if($this-&amp;gt;paar['partnervorname']) { echo &amp;quot;, &amp;quot;.$this-&amp;gt;paar['partnervorname']; &lt;br /&gt;
}; ?&amp;gt; &lt;br /&gt;
&amp;lt;?php if($this-&amp;gt;paar['partnerinnachname']) { echo &amp;quot; und &amp;quot;.$this-&amp;gt;paar['partnerinnachname']; }; ?&amp;gt; &lt;br /&gt;
&amp;lt;?php if($this-&amp;gt;paar['partnerinvorname']) { echo &amp;quot;, &amp;quot;.$this-&amp;gt;paar['partnerinvorname']; }; ?&amp;gt; &lt;br /&gt;
&amp;lt;/h3&amp;gt; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;paar['bild']): ?&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;left&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;?php if($this-&amp;gt;paar['bildfullsize']): ?&amp;gt; &lt;br /&gt;
&amp;lt;a href=&amp;quot;&amp;lt;?php echo $this-&amp;gt;paar['bildfullsize']; ?&amp;gt;&amp;quot; rel=&amp;quot;lightbox[bild]&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;lt;img src=&amp;quot;&amp;lt;?php echo $this-&amp;gt;paar['bild']; ?&amp;gt;&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;?php if($this-&amp;gt;paar['bildfullsize']): ?&amp;gt; &lt;br /&gt;
&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;right&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;ul&amp;gt; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;paar['startklassestandard'] != '-'): ?&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt; &lt;br /&gt;
  &amp;lt;?php echo $this-&amp;gt;paar['startgruppe'].&amp;quot; &amp;quot;.$this-&amp;gt;paar['startklassestandard'].&amp;quot; Standard&amp;quot;; ?&amp;gt; &lt;br /&gt;
&amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;paar['startklasselatein'] != '-'): ?&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt; &lt;br /&gt;
  &amp;lt;?php echo $this-&amp;gt;paar['startgruppe'].&amp;quot; &amp;quot;.$this-&amp;gt;paar['startklasselatein'].&amp;quot; Latein&amp;quot;; ?&amp;gt; &lt;br /&gt;
&amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt; &lt;br /&gt;
   Aktiv: &amp;lt;?php echo $this-&amp;gt;paar['aktivseit']; ?&amp;gt; - &amp;lt;?php if($this-&lt;br /&gt;
&amp;gt;paar['aktivbis']) { echo $this-&amp;gt;paar['aktivbis']; } else { echo &amp;quot;heute&amp;quot;; }; ?&amp;gt; &lt;br /&gt;
&amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;paar['anschrift']): ?&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt; &lt;br /&gt;
   &amp;lt;?php echo nl2br($this-&amp;gt;paar['anschrift']); ?&amp;gt; &lt;br /&gt;
&amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;paar['telefon']): ?&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt; &lt;br /&gt;
   Tel.: &amp;lt;?php echo $this-&amp;gt;paar['telefon']; ?&amp;gt; &lt;br /&gt;
&amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;paar['fax']): ?&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt; &lt;br /&gt;
   Fax: &amp;lt;?php echo $this-&amp;gt;paar['fax']; ?&amp;gt; &lt;br /&gt;
&amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;paar['mobil']): ?&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt; &lt;br /&gt;
   Mob.: &amp;lt;?php echo $this-&amp;gt;paar['mobil']; ?&amp;gt; &lt;br /&gt;
&amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;paar['email']): ?&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt; &lt;br /&gt;
   EMail: {{email::&amp;lt;?php echo $this-&amp;gt;paar['email']; ?&amp;gt;}} &lt;br /&gt;
&amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;paar['homepage']): ?&amp;gt; &lt;br /&gt;
&amp;lt;li&amp;gt; &lt;br /&gt;
   Homepage: &amp;lt;a href=&amp;quot;&amp;lt;?php echo $this-&amp;gt;paar['homepage']; ?&amp;gt;&amp;quot;&amp;gt;&amp;lt;?php echo $this-&amp;gt;paar['homepage']; ?&amp;gt;&amp;lt;/a&amp;gt; &lt;br /&gt;
&amp;lt;/li&amp;gt; &lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt; &lt;br /&gt;
&amp;lt;/ul&amp;gt; &lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&amp;lt;div class=&amp;quot;twocol&amp;quot;&amp;gt; &lt;br /&gt;
&amp;lt;?php echo nl2br($this-&amp;gt;paar['beschreibung']); ?&amp;gt; &lt;br /&gt;
&amp;lt;/div&amp;gt; &lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Im Prinzip nichts besonderes, ich bastele aus den Namen eine schöne Überschrift, Bild und die anderen Texte werden in DIVs verpackt, die ich per CSS dann &amp;quot;hübsch&amp;quot; anordne. Beim Bild wird unser Modulcode in ''$paar['bild']'' eine verkleinerte Version (180px breit max.) zurückliefern, in ''$paar['bildfullsize']'' befindet sich das Originalbild, das hier im Template dann über eine Lightbox großklickbar ist. Das Array ''$paar'' im Template entspricht ansonsten den Datenbankfeldern in ''tl_gw_turnierpaare''.&lt;br /&gt;
&lt;br /&gt;
Die Hauptarbeit passiert nun in der Frontend-Modul-Klasse ''/system/modules/gw_turnierpaare/gwTurnierpaarliste.php'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class gwTurnierpaarliste extends Module &lt;br /&gt;
{ &lt;br /&gt;
    /** &lt;br /&gt;
     * Template &lt;br /&gt;
     * @var string &lt;br /&gt;
     */ &lt;br /&gt;
    protected $strTemplate = 'gw_turnierpaarliste'; &lt;br /&gt;
  protected $strDetailKey = 'info';&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
Zunächst definiere ich wie üblich den &amp;quot;Default&amp;quot;-Templatenamen, das ist der für die gesamte Liste. Zusätzlich definiere ich hier das URL-Fragment, was meinen &amp;quot;Detail-Link&amp;quot; ausmachen soll.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  function obj2Arr($objPaar) &lt;br /&gt;
  { &lt;br /&gt;
    $newArr = array &lt;br /&gt;
      ( &lt;br /&gt;
        'partnernachname' =&amp;gt; trim($objPaar-&amp;gt;partnernachname), &lt;br /&gt;
        'partnervorname' =&amp;gt; trim($objPaar-&amp;gt;partnervorname), &lt;br /&gt;
        'partnerinnachname' =&amp;gt; trim($objPaar-&amp;gt;partnerinnachname), &lt;br /&gt;
        'partnerinvorname' =&amp;gt; trim($objPaar-&amp;gt;partnerinvorname), &lt;br /&gt;
        'startgruppe' =&amp;gt; $objPaar-&amp;gt;startgruppe, &lt;br /&gt;
        'startklasselatein' =&amp;gt; $objPaar-&amp;gt;startklasselatein, &lt;br /&gt;
        'startklassestandard' =&amp;gt; $objPaar-&amp;gt;startklassestandard, &lt;br /&gt;
        'aktiv' =&amp;gt; $objPaar-&amp;gt;aktiv, &lt;br /&gt;
        'aktivseit' =&amp;gt; $objPaar-&amp;gt;aktivseit, &lt;br /&gt;
        'aktivbis' =&amp;gt; $objPaar-&amp;gt;aktivbis, &lt;br /&gt;
        'id' =&amp;gt; $objPaar-&amp;gt;id, &lt;br /&gt;
        'beschreibung' =&amp;gt; $objPaar-&amp;gt;beschreibung, &lt;br /&gt;
      ); &lt;br /&gt;
      if($objPaar-&amp;gt;zeigeanschrift == '1') &lt;br /&gt;
      { &lt;br /&gt;
        $newArr['anschrift'] = $objPaar-&amp;gt;anschrift; &lt;br /&gt;
      } &lt;br /&gt;
      if($objPaar-&amp;gt;zeigetelefon == '1') &lt;br /&gt;
      { &lt;br /&gt;
        $newArr['telefon'] = $objPaar-&amp;gt;telefon; &lt;br /&gt;
      }&lt;br /&gt;
      if($objPaar-&amp;gt;zeigefax == '1') &lt;br /&gt;
      { &lt;br /&gt;
        $newArr['fax'] = $objPaar-&amp;gt;fax; &lt;br /&gt;
      } &lt;br /&gt;
      if($objPaar-&amp;gt;zeigemobil == '1') &lt;br /&gt;
      { &lt;br /&gt;
        $newArr['mobil'] = $objPaar-&amp;gt;mobil; &lt;br /&gt;
      } &lt;br /&gt;
      if($objPaar-&amp;gt;zeigeemail == '1') &lt;br /&gt;
      { &lt;br /&gt;
        $newArr['email'] = $objPaar-&amp;gt;email; &lt;br /&gt;
      } &lt;br /&gt;
      if($objPaar-&amp;gt;zeigehomepage == '1') &lt;br /&gt;
      { &lt;br /&gt;
        $newArr['homepage'] = $objPaar-&amp;gt;homepage; &lt;br /&gt;
      } &lt;br /&gt;
    return $newArr; &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
Diese Utility-Funktion füllt mir eine Zeile des Resultsets der Datenbank in ein Array. Ich brauche das an zwei Stellen, darum habe ich das hierhin ausgelagert. Hier werden auch schon die ''zeige''-Flags berücksichtigt: Sind die nicht angehakt, landet auch nichts im Array. Damit spare ich mir die Abfragen im Template.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;		&lt;br /&gt;
    protected function compile() &lt;br /&gt;
    { &lt;br /&gt;
        if ( strlen($this-&amp;gt;Input-&amp;gt;get($this-&amp;gt;strDetailKey)) ) &lt;br /&gt;
        { &lt;br /&gt;
      // A &amp;quot;detail&amp;quot;-URL is given -&amp;gt; Output turnierpaarliste_detail template &lt;br /&gt;
      $this-&amp;gt;compileDetailTemplate(); &lt;br /&gt;
    } &lt;br /&gt;
    else &lt;br /&gt;
    { &lt;br /&gt;
      // Output the turnierpaarliste template &lt;br /&gt;
      $this-&amp;gt;compileListTemplate(); &lt;br /&gt;
      } &lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Die alte ''compile()''-Funktion wurde angenehm kurz. Falls der GET-Parameter mit dem Namen ''info'' gesetzt ist (über unsere URL turnierpaarliste/info/8.html), dann wird eine Funktion zur Ausgabe des Detail-Templates aufgerufen, ansonsten eine für das Listentemplate.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // Compiles the turnierpaarliste template &lt;br /&gt;
  protected function compileListTemplate() &lt;br /&gt;
  { &lt;br /&gt;
        $moduleParams = $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;SELECT * FROM tl_module WHERE id=?&amp;quot;) &lt;br /&gt;
                -&amp;gt;limit(1) &lt;br /&gt;
                -&amp;gt;execute($this-&amp;gt;id); &lt;br /&gt;
    $whereClause = ''; &lt;br /&gt;
    if($moduleParams-&amp;gt;gw_tp_showonlyactive == 'A') &lt;br /&gt;
    { &lt;br /&gt;
      $whereClause = &amp;quot;WHERE aktiv='1'&amp;quot;; &lt;br /&gt;
    } &lt;br /&gt;
    else &lt;br /&gt;
    { &lt;br /&gt;
      if($moduleParams-&amp;gt;gw_tp_showonlyactive == 'I') &lt;br /&gt;
      { &lt;br /&gt;
        $whereClause = &amp;quot;WHERE aktiv=''&amp;quot;; &lt;br /&gt;
      } &lt;br /&gt;
    } &lt;br /&gt;
    $orderClause = 'partnernachname, partnerinnachname'; &lt;br /&gt;
    if($moduleParams-&amp;gt;gw_tp_couplesorting == 'C') &lt;br /&gt;
    { &lt;br /&gt;
      // Nach Altersgruppen sortieren &lt;br /&gt;
      $fieldstartgruppe=&amp;quot;''&amp;quot;; &lt;br /&gt;
       foreach(array('KIN I','KIN II', 'JUN I', 'JUN II', 'JUG', 'HGR', 'HGR II', 'SEN I', 'SEN II', 'SEN III', 'SEN IV') as $gruppe) &lt;br /&gt;
      { &lt;br /&gt;
        $fieldstartgruppe .= &amp;quot;,'&amp;quot;.$gruppe.&amp;quot;'&amp;quot;; &lt;br /&gt;
      } &lt;br /&gt;
      $fieldstartklasse=&amp;quot;''&amp;quot;; &lt;br /&gt;
      foreach(array('-', 'E','D', 'C', 'B', 'A', 'S', 'PRO', 'LL', 'OL', 'RL', '2. BL', '1. BL') as $klasse) &lt;br /&gt;
      { &lt;br /&gt;
        $fieldstartklasse .= &amp;quot;,'&amp;quot;.$klasse.&amp;quot;'&amp;quot;; &lt;br /&gt;
      } &lt;br /&gt;
      $orderClause = &amp;quot;FIELD(startgruppe,&amp;quot;.$fieldstartgruppe.&amp;quot;), FIELD(startklassestandard,&amp;quot;.$fieldstartklasse.&amp;quot;), FIELD(startklasselatein,&amp;quot;.$fieldstartklasse.&amp;quot;), partnernachname, partnerinnachname&amp;quot;; &lt;br /&gt;
    } &lt;br /&gt;
    $arrPaare = array(); &lt;br /&gt;
    $objPaare = $this-&amp;gt;Database-&amp;gt;execute(&amp;quot;SELECT * FROM tl_gw_turnierpaare &amp;quot; . $whereClause . &amp;quot;ORDER BY &amp;quot; . $orderClause); &lt;br /&gt;
    while ($objPaare-&amp;gt;next()) &lt;br /&gt;
    { &lt;br /&gt;
      $newArr = $this-&amp;gt;obj2Arr($objPaare); &lt;br /&gt;
      if(strlen($objPaare-&amp;gt;bild) == 0) &lt;br /&gt;
      { &lt;br /&gt;
        $newArr['bild'] = '/system/modules/gw_turnierpaare/icons/default.png'; &lt;br /&gt;
      } &lt;br /&gt;
      else &lt;br /&gt;
      { &lt;br /&gt;
        $newArr['bild'] = $this-&amp;gt;getImage($objPaare-&amp;gt;bild, '', '48'); &lt;br /&gt;
      } &lt;br /&gt;
      $arrPaare[] = $newArr; &lt;br /&gt;
    } &lt;br /&gt;
    $this-&amp;gt;Template-&amp;gt;paare = $arrPaare; &lt;br /&gt;
  }  &lt;br /&gt;
 &amp;lt;/pre&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Bei der Ausgabe des Listentemplates hat sich nicht viel gegenüber dem letzten Schritt getan, nur die Utility-Funktion obj2Arr wird jetzt benutzt, um den Großteil der Felder aus der Datenbank ins Array zu packen. Als Paarbild wird ein Thumbnail von max. 48 Pixeln Höhe ausgegeben.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;	 &lt;br /&gt;
  // Compiles the data for the turnierparliste_detail template &lt;br /&gt;
  protected function compileDetailTemplate() &lt;br /&gt;
  { &lt;br /&gt;
    $coupleRow = $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;SELECT * FROM tl_gw_turnierpaare WHERE id=?&amp;quot;) &lt;br /&gt;
            -&amp;gt;limit(1) &lt;br /&gt;
            -&amp;gt;execute($this-&amp;gt;Input-&amp;gt;get($this-&amp;gt;strDetailKey)); &lt;br /&gt;
    $this-&amp;gt;strTemplate = 'gw_turnierpaarliste_detail'; &lt;br /&gt;
    $this-&amp;gt;Template = new FrontendTemplate($this-&amp;gt;strTemplate); &lt;br /&gt;
    $newArr = $this-&amp;gt;obj2Arr($coupleRow); &lt;br /&gt;
    if(strlen($coupleRow-&amp;gt;bild) == 0) &lt;br /&gt;
    { &lt;br /&gt;
      $newArr['bild'] = '/system/modules/gw_turnierpaare/icons/default.png'; &lt;br /&gt;
    } &lt;br /&gt;
    else &lt;br /&gt;
    { &lt;br /&gt;
      $newArr['bild'] = $this-&amp;gt;getImage($coupleRow-&amp;gt;bild, '180', ''); &lt;br /&gt;
      $newArr['bildfullsize'] = $coupleRow-&amp;gt;bild; &lt;br /&gt;
    } &lt;br /&gt;
    $this-&amp;gt;Template-&amp;gt;paar = $newArr; &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier die Ausgabe des Detail-Templates: Zunächst holen wir uns das Paar aus der Datenbank, dessen Detailseite ausgegeben werden soll. Hier wäre wohl zukünftig noch eine Fehlerabfrage (&amp;quot;ID existiert nicht&amp;quot;) notwendig. &lt;br /&gt;
''Hüstel''&lt;br /&gt;
&lt;br /&gt;
Dann müssen wir das andere Template wählen. Dafür ersetze ich den Namen durch den Neuen. Das alleine reichte aber nicht: Es erschien immer noch das alte Template, weil es schon initialisiert war, als ''compile()'' aufgerufen wurde. &lt;br /&gt;
&lt;br /&gt;
Eine Änderung von ''$strTemplate'' bleibt dann unbemerkt. Darum muss jetzt in der nächsten Zeile ein neues Frontendtemplate instanziert werden. Ich hätte den Namen auch direkt als Parameter bei der Instanzierung angeben können. Dann fülle ich mit ''obj2Arr()'' mein Paar-Array, und gebe (falls vorhanden) das Paarbild-Thumbnail mit maximal 180 Pixel Breite aus, und zusätzlich das Originalbild.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis ist das Folgende - die Turnierpaarliste:&lt;br /&gt;
  &lt;br /&gt;
[[Datei:gw_turnierpaare_23.jpg]]&lt;br /&gt;
&lt;br /&gt;
Ich habe das Default-Bild noch ausgetauscht, das angezeigt wird, wenn kein Paarbild hinterlegt ist (Ich hänge es auch hier nochmal an). Das &amp;quot;richtige&amp;quot; Paarbild ist übrigens ein freies aus Wikimedia Commons.&lt;br /&gt;
 &lt;br /&gt;
Nach Klick auf einen Detaillink:&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_24.png]]&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-08_Frontend_Parametrisierung</id>
		<title>TEE-08 Frontend Parametrisierung</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-08_Frontend_Parametrisierung"/>
				<updated>2010-07-07T19:57:38Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Param…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Parameter fürs Modul=&lt;br /&gt;
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 &amp;quot;Nachnamen alphabetisch&amp;quot; und &amp;quot;Nach Altersgruppe aufsteigend&amp;quot; wählbar sein.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Also habe ich neue Felder angelegt. In der ''config/database.php'' meiner Extension:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--&lt;br /&gt;
-- Extend table 'tl_module'&lt;br /&gt;
--&lt;br /&gt;
CREATE TABLE `tl_module` (&lt;br /&gt;
  `gw_tp_showonlyactive` char(1) NOT NULL default 'B',&lt;br /&gt;
  `gw_tp_couplesorting` char(1) NOT NULL default 'A',&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
	 &lt;br /&gt;
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 &amp;quot;CREATE TABLE&amp;quot; verwenden. Das Installtool macht das Richtige daraus...&lt;br /&gt;
&lt;br /&gt;
Danach muss ich das Installtool aufrufen, um die neuen Felder anlegen zu lassen.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Dafür nehmen wir uns ''system/modules/gw_turnierpaare/dca/tl_module.php'' vor:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$GLOBALS['TL_DCA']['tl_module']['palettes']['gw_turnierpaarliste'] = '{title_legend},name,headline,type;{sort_legend},gw_tp_showonlyactive,gw_tp_couplesorting;&lt;br /&gt;
{protected_legend:hide},protected;{expert_legend:hide},guests,cssID,space';  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Die müssen noch im DCA definiert werden:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$GLOBALS['TL_DCA']['tl_module']['fields']['gw_tp_showonlyactive'] = array &lt;br /&gt;
( &lt;br /&gt;
    'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_module']['gw_tp_showonlyactive'], &lt;br /&gt;
    'default'                 =&amp;gt; 'B', &lt;br /&gt;
    'exclude'                 =&amp;gt; true, &lt;br /&gt;
    'inputType'               =&amp;gt; 'select', &lt;br /&gt;
    'options'                 =&amp;gt; array('B','A','I'), &lt;br /&gt;
    'reference'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_module']['gw_tp_filteroptions'], &lt;br /&gt;
    'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
); &lt;br /&gt;
$GLOBALS['TL_DCA']['tl_module']['fields']['gw_tp_couplesorting'] = array &lt;br /&gt;
( &lt;br /&gt;
    'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_module']['gw_tp_couplesorting'], &lt;br /&gt;
    'default'                 =&amp;gt; 'A', &lt;br /&gt;
    'exclude'                 =&amp;gt; true, &lt;br /&gt;
    'inputType'               =&amp;gt; 'select', &lt;br /&gt;
    'options'                 =&amp;gt; array('A','C'), &lt;br /&gt;
    'reference'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_module']['gw_tp_sortoptions'], &lt;br /&gt;
    'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true) &lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
	   &lt;br /&gt;
Der Typ ist ''select'', also eine Dropdownbox. 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 erstmal 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.&lt;br /&gt;
&lt;br /&gt;
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 weiss nicht, was da &amp;quot;best practice&amp;quot; ist.&lt;br /&gt;
&lt;br /&gt;
Wir ergänzen also die ''modules.php'' um:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Back end fields for tl_module &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_module']['sort_legend']     = 'Filter und Sortierung'; &lt;br /&gt;
  &lt;br /&gt;
$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'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_module']['gw_tp_filteroptions'] = array('B' =&amp;gt; 'Alle Paare', 'A' =&amp;gt; 'Nur aktive Paare', 'I' =&amp;gt; 'Nur inaktive Paare'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_module']['gw_tp_couplesorting'] = array('Sortiermodus', 'Bitte wählen Sie aus, wie die Liste der Turnierpaare sortiert sein soll'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_module']['gw_tp_sortoptions'] = array('A' =&amp;gt; 'Alphabetisch', 'C' =&amp;gt; 'Nach Altersklasse aufsteigend');&lt;br /&gt;
 &amp;lt;/pre&amp;gt; &lt;br /&gt;
	  &lt;br /&gt;
Hier kommt nun der Knackpunkt der ''reference''-Arrays, der mir nicht klar war, und erst durch Abgucken bei anderen Extensions geklärt wurde:&lt;br /&gt;
&lt;br /&gt;
Das ''reference''-Array darf nicht einfach ein aufsteigendes Array der Texte zu den Optionen sein wie das ''options''-Array (also &amp;quot;array('text1','text2','text3');&amp;quot;), sondern es muss ein assoziatives Array mit der Beziehung 'option1' =&amp;gt; 'Text1' sein, sonst funktioniert es nicht. Die DCA-Referenz bleibt da leider sehr schwammig. &lt;br /&gt;
&lt;br /&gt;
Auch die Abschnittsüberschrift ''sort_legend'' definieren wir hier.&lt;br /&gt;
&lt;br /&gt;
Damit haben wir dieses Ergebnis:&lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_021.png]]&lt;br /&gt;
&lt;br /&gt;
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. &lt;br /&gt;
	 &lt;br /&gt;
==Parameter fürs Modul, die Zweite==&lt;br /&gt;
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'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $moduleParams = $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;SELECT * FROM tl_module WHERE id=?&amp;quot;) &lt;br /&gt;
                        -&amp;gt;limit(1) &lt;br /&gt;
                        -&amp;gt;execute($this-&amp;gt;id); &lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
	 								&lt;br /&gt;
''$this-&amp;gt;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.&lt;br /&gt;
&lt;br /&gt;
Die muss ich nun auswerten uns entsprechend reagieren. Zunächst das Flag, das mir nur die aktiven Paare, nur die inaktiven oder beide liefert:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
    $whereClause = ''; &lt;br /&gt;
    if($moduleParams-&amp;gt;gw_tp_showonlyactive == 'A') &lt;br /&gt;
    { &lt;br /&gt;
      $whereClause = &amp;quot;WHERE aktiv='1'&amp;quot;; &lt;br /&gt;
    } &lt;br /&gt;
    else &lt;br /&gt;
    { &lt;br /&gt;
      if($moduleParams-&amp;gt;gw_tp_showonlyactive == 'I') &lt;br /&gt;
      { &lt;br /&gt;
        $whereClause = &amp;quot;WHERE aktiv=''&amp;quot;; &lt;br /&gt;
      } &lt;br /&gt;
    } &lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
	 	 &lt;br /&gt;
Die Variable ''$whereClause'' baue ich später in meinen SELECT der Turnierpaare ein.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Der erste Fall ist einfach (&amp;quot;ORDER BY partnernachname, partnerinnachname&amp;quot;), 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 &amp;quot;BCA&amp;quot; sortieren, leistet das &amp;quot;ORDER BY FIELD(field,'B','C','A')&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $orderClause = 'partnernachname, partnerinnachname'; &lt;br /&gt;
    if($moduleParams-&amp;gt;gw_tp_couplesorting == 'C') &lt;br /&gt;
    { &lt;br /&gt;
      // Nach Altersgruppen sortieren &lt;br /&gt;
      $fieldstartgruppe=&amp;quot;''&amp;quot;; &lt;br /&gt;
       foreach(array('KIN I','KIN II', 'JUN I', 'JUN II', 'JUG', 'HGR', 'HGR II', 'SEN I', 'SEN II', 'SEN III', 'SEN IV') as $gruppe) &lt;br /&gt;
      { &lt;br /&gt;
        $fieldstartgruppe .= &amp;quot;,'&amp;quot;.$gruppe.&amp;quot;'&amp;quot;; &lt;br /&gt;
      } &lt;br /&gt;
      $fieldstartklasse=&amp;quot;''&amp;quot;; &lt;br /&gt;
      foreach(array('-', 'E','D', 'C', 'B', 'A', 'S', 'PRO', 'LL', 'OL', 'RL', '2. BL', '1. BL') as $klasse) &lt;br /&gt;
      { &lt;br /&gt;
        $fieldstartklasse .= &amp;quot;,'&amp;quot;.$klasse.&amp;quot;'&amp;quot;; &lt;br /&gt;
      } &lt;br /&gt;
       &lt;br /&gt;
      $orderClause = &amp;quot;FIELD(startgruppe,&amp;quot;.$fieldstartgruppe.&amp;quot;), FIELD(startklassestandard,&amp;quot;.$fieldstartklasse.&amp;quot;), FIELD(startklasselatein,&amp;quot;.$fieldstartklasse.&amp;quot;), partnernachname, partnerinnachname&amp;quot;; &lt;br /&gt;
    }  &lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
	 &lt;br /&gt;
Defaultmäßig wird nach den Nachnamen alphabetisch 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 &amp;quot;ORDER BY&amp;quot;-Teil zusammengebaut wird.&lt;br /&gt;
&lt;br /&gt;
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überzulaufen, um daraus wieder einen String zu machen. &lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
 &lt;br /&gt;
Darum bleibt es erstmal bei der Schleife über den Arrayelementen.&lt;br /&gt;
&lt;br /&gt;
Schließlich muss das ursprüngliche SELECT-Statement noch um die neuen Variablen ''$whereClause'' und ''$orderClause'' erweitert werden:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $objPaare = $this-&amp;gt;Database-&amp;gt;execute(&amp;quot;SELECT * FROM tl_gw_turnierpaare &amp;quot; . $whereClause . &amp;quot;ORDER BY &amp;quot; . $orderClause); &lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
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 in in eine Seite als Inhaltselemente ein.&lt;br /&gt;
&lt;br /&gt;
Das Ergebnis:	 &lt;br /&gt;
&lt;br /&gt;
[[Datei:gw_turnierpaare_022.png]]&lt;br /&gt;
&lt;br /&gt;
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 &amp;quot;Detail&amp;quot;-Link gehen.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_022.png</id>
		<title>Datei:Gw turnierpaare 022.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_022.png"/>
				<updated>2010-07-07T19:56:37Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-08 Frontend Parametrisierung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-08 Frontend Parametrisierung&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_021.png</id>
		<title>Datei:Gw turnierpaare 021.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_021.png"/>
				<updated>2010-07-07T19:54:57Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-08 Frontend Parametrisierung&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-08 Frontend Parametrisierung&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_020.png</id>
		<title>Datei:Gw turnierpaare 020.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_020.png"/>
				<updated>2010-07-07T19:46:28Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-07 Frontend Simpel-Version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-07 Frontend Simpel-Version&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_20.png</id>
		<title>Datei:Gw turnierpaare 20.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_20.png"/>
				<updated>2010-07-07T19:44:54Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: hat eine neue Version von „Datei:Gw turnierpaare 20.png“ hochgeladen:&amp;amp;#32;TEE-07 Frontend Simpel-Version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-01&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_019.png</id>
		<title>Datei:Gw turnierpaare 019.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_019.png"/>
				<updated>2010-07-07T19:42:40Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-07 Frontend Simpel-Version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-07 Frontend Simpel-Version&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_018.png</id>
		<title>Datei:Gw turnierpaare 018.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_018.png"/>
				<updated>2010-07-07T19:41:09Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-07 Frontend Simpel-Version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-07 Frontend Simpel-Version&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-07_Frontend_Simpel-Version</id>
		<title>TEE-07 Frontend Simpel-Version</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-07_Frontend_Simpel-Version"/>
				<updated>2010-07-07T19:35:21Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Endli…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Endlich Frontend!=&lt;br /&gt;
nach soviel Kampf hinter den Kulissen wird jetzt endlich was im Frontend angezeigt und - um das vorweg zu nehmen - das klappt ziemlich reibungslos.&lt;br /&gt;
&lt;br /&gt;
Zunächst mache ich eine &amp;quot;Simpel-Version&amp;quot; des Frontends, die erstmal was anzeigt. Verfeinerungsschritte kommen dann nach und nach dazu. Erstmal muss das schnelle Erfolgserlebnis her.&lt;br /&gt;
&lt;br /&gt;
Zunächst mal müssen die Frontendmodule in ''system/modules/gw_turnierpaare/config/config.php'' &amp;quot;registriert&amp;quot; werden:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Front end module &lt;br /&gt;
array_insert($GLOBALS['FE_MOD']['turnierpaare'], 0, array &lt;br /&gt;
( &lt;br /&gt;
    'gw_turnierpaarliste'	=&amp;gt; 'gwTurnierpaarliste', &lt;br /&gt;
    'gw_meldeliste'			=&amp;gt; 'gwMeldeliste' &lt;br /&gt;
)); &lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
	  &lt;br /&gt;
''turnierpaare'' scheint die Zwischenüberschrift zu sein, die man in der Dropdownliste der zur Verfügung stehenden Module zu sehen kriegt. Die Keys in dem Array sind einfach nur die Bezeichner, die durch die Languagefiles auch übersetzt werden. Die Values dahinter sind die Namen der Frontendklassen. Zu jeder Frontendklasse existiert ''/system/modules/gw_turnierpaare/*.php'' mit der entsprechenden Klassendefinition.&lt;br /&gt;
&lt;br /&gt;
Damit in der Modul-Dropdown-Liste nicht das hässliche ''turnierpaare'' steht, muss die Languagedatei erweitert werden, z.b. ''system/modules/gw_turnierpaare/languages/de/modules.php'' um:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$GLOBALS['TL_LANG']['FMD']['turnierpaare'] = array('Turnierpaare'); &lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
	  &lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class gwTurnierpaarliste extends Module &lt;br /&gt;
{ &lt;br /&gt;
    /** &lt;br /&gt;
     * Template &lt;br /&gt;
     * @var string &lt;br /&gt;
     */ &lt;br /&gt;
    protected $strTemplate = 'gw_turnierpaarliste'; &lt;br /&gt;
    /** &lt;br /&gt;
     * Generate module &lt;br /&gt;
     */ &lt;br /&gt;
    protected function compile() &lt;br /&gt;
    { &lt;br /&gt;
    $arrPaare = array(); &lt;br /&gt;
    $objPaare = $this-&amp;gt;Database-&amp;gt;execute(&amp;quot;SELECT * FROM tl_gw_turnierpaare ORDER BY partnernachname, partnerinnachname&amp;quot;); &lt;br /&gt;
    while ($objPaare-&amp;gt;next()) &lt;br /&gt;
    { &lt;br /&gt;
      $newArr = array &lt;br /&gt;
      ( &lt;br /&gt;
        'partnernachname' =&amp;gt; trim($objPaare-&amp;gt;partnernachname), &lt;br /&gt;
        'partnervorname' =&amp;gt; trim($objPaare-&amp;gt;partnervorname), &lt;br /&gt;
        'partnerinnachname' =&amp;gt; trim($objPaare-&amp;gt;partnerinnachname), &lt;br /&gt;
        'partnerinvorname' =&amp;gt; trim($objPaare-&amp;gt;partnerinvorname), &lt;br /&gt;
        'startgruppe' =&amp;gt; $objPaare-&amp;gt;startgruppe, &lt;br /&gt;
        'startklasselatein' =&amp;gt; $objPaare-&amp;gt;startklasselatein, &lt;br /&gt;
        'startklassestandard' =&amp;gt; $objPaare-&amp;gt;startklassestandard, &lt;br /&gt;
        'aktiv' =&amp;gt; $objPaare-&amp;gt;aktiv, &lt;br /&gt;
        'aktivseit' =&amp;gt; $objPaare-&amp;gt;aktivseit, &lt;br /&gt;
        'aktivbis' =&amp;gt; $objPaare-&amp;gt;aktivbis, &lt;br /&gt;
      ); &lt;br /&gt;
       &lt;br /&gt;
      if(strlen($objPaare-&amp;gt;bild) == 0) &lt;br /&gt;
      { &lt;br /&gt;
        $newArr['bild'] = '/system/modules/gw_turnierpaare/icons/default.png'; &lt;br /&gt;
      } &lt;br /&gt;
      else &lt;br /&gt;
      { &lt;br /&gt;
        $newArr['bild'] = $this-&amp;gt;getImage($objPaare-&amp;gt;bild, '30', '30'); &lt;br /&gt;
      } &lt;br /&gt;
       &lt;br /&gt;
      $arrPaare[] = $newArr; &lt;br /&gt;
    } &lt;br /&gt;
    $this-&amp;gt;Template-&amp;gt;paare = $arrPaare; &lt;br /&gt;
    } &lt;br /&gt;
}  &lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
	 &lt;br /&gt;
Wir leiten von ''Module'' ab, und ''$strTemplate'' enthält den Namen des Templates, was wir füllen wollen. Die Funktion, die die Werte für das Template liefert, muss ''compile()'' heißen.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Dann wird das 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.&lt;br /&gt;
&lt;br /&gt;
Nun das Ausgabetemplate ''system/modules/gw_turnierpaare/templates/gw_turnierpaarliste.tpl'':&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;&amp;lt;?php echo $this-&amp;gt;class; ?&amp;gt;&amp;quot;&amp;lt;?php echo $this-&amp;gt;cssID; ?&amp;gt;&amp;lt;?php if ($this-&lt;br /&gt;
&amp;gt;style): ?&amp;gt; style=&amp;quot;&amp;lt;?php echo $this-&amp;gt;style; ?&amp;gt;&amp;quot;&amp;lt;?php endif; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;?php if ($this-&amp;gt;headline): ?&amp;gt;&lt;br /&gt;
&amp;lt;&amp;lt;?php echo $this-&amp;gt;hl; ?&amp;gt;&amp;gt;&amp;lt;?php echo $this-&amp;gt;headline; ?&amp;gt;&amp;lt;/&amp;lt;?php echo $this-&amp;gt;hl; ?&amp;gt;&amp;gt;&lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt;&lt;br /&gt;
&amp;lt;table cellpadding=&amp;quot;4&amp;quot; cellspacing=&amp;quot;0&amp;quot; summary=&amp;quot;Turnierpaarliste&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;thead&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;th&amp;gt;&amp;amp;nbsp;&amp;lt;/th&amp;gt;&lt;br /&gt;
      &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;&lt;br /&gt;
      &amp;lt;th&amp;gt;Startgruppe&amp;lt;/th&amp;gt;&lt;br /&gt;
      &amp;lt;th&amp;gt;Std&amp;lt;/th&amp;gt;&lt;br /&gt;
      &amp;lt;th&amp;gt;Lat&amp;lt;/th&amp;gt;&lt;br /&gt;
      &amp;lt;th&amp;gt;Aktiv seit&amp;lt;/th&amp;gt;&lt;br /&gt;
      &amp;lt;th&amp;gt; Aktiv bis&amp;lt;/th&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
  &amp;lt;/thead&amp;gt;&lt;br /&gt;
  &amp;lt;tbody&amp;gt;&lt;br /&gt;
&amp;lt;?php foreach ($this-&amp;gt;paare as $paar): ?&amp;gt;&lt;br /&gt;
  &amp;lt;tr&amp;lt;?php if($paar['aktiv'] != '1') { echo ' style=&amp;quot;color: #888;&amp;quot;'; } ?&amp;gt;&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&lt;br /&gt;
  &amp;lt;img src=&amp;quot;&amp;lt;?php echo $paar['bild']; ?&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;?php echo $paar['partnernachname']; ?&amp;gt;&lt;br /&gt;
&amp;lt;?php if($paar['partnervorname']): ?&amp;gt;&lt;br /&gt;
&amp;lt;?php   echo ', '.$paar['partnervorname']; ?&amp;gt;&lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt;&lt;br /&gt;
&amp;lt;?php if($paar['partnerinnachname']): ?&amp;gt;&lt;br /&gt;
&amp;lt;?php   echo ' und '.$paar['partnerinnachname']; ?&amp;gt;&lt;br /&gt;
&amp;lt;?php   if($paar['partnerinvorname']): ?&amp;gt;&lt;br /&gt;
&amp;lt;?php     echo ', '.$paar['partnerinvorname']; ?&amp;gt;&lt;br /&gt;
&amp;lt;?php   endif; ?&amp;gt;&lt;br /&gt;
&amp;lt;?php endif; ?&amp;gt;&lt;br /&gt;
  &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;?php echo $paar['startgruppe']; ?&amp;gt;&lt;br /&gt;
  &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;?php echo $paar['startklassestandard']; ?&amp;gt;&lt;br /&gt;
  &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;?php echo $paar['startklasselatein']; ?&amp;gt;&lt;br /&gt;
  &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;?php echo $paar['aktivseit']; ?&amp;gt;&lt;br /&gt;
  &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;td&amp;gt;&amp;lt;?php echo $paar['aktivbis']; ?&amp;gt;&lt;br /&gt;
  &amp;lt;/td&amp;gt;&lt;br /&gt;
  &amp;lt;/tr&amp;gt;&amp;lt;?php endforeach; ?&amp;gt;&lt;br /&gt;
  &amp;lt;/tbody&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
	 &lt;br /&gt;
Den Teil bis zum Beginn der Table habe ich aus einem anderen Template übernommen, und enthält den &amp;quot;Standardheader&amp;quot; mit der Möglichkeit, spezielle Klassen, IDs und Styles anzugeben. Auch eine Überschrift wird zugelassen, falls sie gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
In der Tabelle selbst wird ein Kopfbereich definiert mit den Spaltenüberschriften.&lt;br /&gt;
&lt;br /&gt;
Dann werden alle Paare in der Paarliste (Variable ''$this-&amp;gt;paare'') durchlaufen. Falls das Paar NICHT aktiv ist, setze ich einen style für die Tabellenzeile (graue Schrift). Das ist so nicht &amp;quot;sauber&amp;quot; und wird auch so nicht bleiben, sondern durch richtiges CSS-Markup ersetzt. Erstmal dient es zur Visualisierung.&lt;br /&gt;
&lt;br /&gt;
Aus den Namen von Herr und Dame wird ein &amp;quot;schöner&amp;quot; Namensstring zusammengebaut und ausgegeben. Die rechtlichen Felder werden ziemlich straight-forward ausgegeben.&lt;br /&gt;
&lt;br /&gt;
Nun wären wir eigentlich &amp;quot;fast&amp;quot; fertig. Aber um unser neues Frondendmodul nutzen zu können, muss es im Backend unter &amp;quot;Module&amp;quot; angelegt werden. Das übernimmt die Backend-Klasse ''tl_module'', und die weiss noch nichts detailliertes über unser neues Frontendmodul.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
In die ''tl_module.php'' kommt:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php &lt;br /&gt;
// Add a palette to tl_module &lt;br /&gt;
$GLOBALS['TL_DCA']['tl_module']['palettes']['gw_turnierpaarliste'] = 'name,type,headline;align,space,cssID'; &lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
	  &lt;br /&gt;
Wenn in der Modulverwaltung in der Drop-Down-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.&lt;br /&gt;
&lt;br /&gt;
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!&lt;br /&gt;
&lt;br /&gt;
Jetzt können wir das neue Modul in der Modulverwaltung anlegen:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Gw_turnierpaare_018.png]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:Gw_turnierpaare_019.png]]&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Jetzt können wir das Modul einem Artikel hinzufügen, und bei mir sieht es dann so aus:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Gw_turnierpaare_020.png]]&lt;br /&gt;
&lt;br /&gt;
Gut, das Icon ist auf meinem Hintergrund noch nicht &amp;quot;hübsch&amp;quot;, 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.&lt;br /&gt;
&lt;br /&gt;
Damit genug für heute, ein erstes Ergebnis ist erreicht, aber das Frontendmodul wird noch deutlich aufgebohrt werden. In den nächsten Folgen ;-). &lt;br /&gt;
		&lt;br /&gt;
==Ein wenig Finetuning==&lt;br /&gt;
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. &lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php &lt;br /&gt;
// Add a palette to tl_module &lt;br /&gt;
$GLOBALS['TL_DCA']['tl_module']['palettes']['gw_turnierpaarliste'] = '{title_legend},name,headline,type;{protected_legend:hide},protected;&lt;br /&gt;
{expert_legend:hide},guests,cssID,space'; &lt;br /&gt;
?&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
	 &lt;br /&gt;
Damit haben wir schöne Palettenüberschriften und den &amp;quot;Standardsatz&amp;quot; an Eigenschaften für Module.&lt;br /&gt;
&lt;br /&gt;
Dann hatte ich das hier entdeckt: [http://www.contao.org/blog-leser/items/auf-den-aktiven-datensatz-im-dca-zugreifen.html 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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
==Diskussion==&lt;br /&gt;
'''user: Toflar'''&lt;br /&gt;
&lt;br /&gt;
Als kleine Ergänzung. Ich finde das passt gerade schön hier rein:&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if(version_compare(VERSION . '.' . BUILD, '2.8.0', '&amp;lt;')) &lt;br /&gt;
{ &lt;br /&gt;
   // mach für Versionen unter 2.8.0 das &lt;br /&gt;
} &lt;br /&gt;
else &lt;br /&gt;
{ &lt;br /&gt;
   // ab Version 2.8.0 mach das &lt;br /&gt;
}  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-00_Vorbemerkung</id>
		<title>TEE-00 Vorbemerkung</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-00_Vorbemerkung"/>
				<updated>2010-07-07T19:16:17Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung / Vorbemerkungen der Wiki-Autoren&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Vorbemerkungen=&lt;br /&gt;
* Die Artikel nehmen einen sehr ausführlichen Forumsthread aus dem Contao-Community-Forum ''Allgemeine Infos für Third-Party Extensions -&amp;gt; Entwickler-Tutorials'' auf, der unter dem Titel ''Tagebuch einer Extension-Entwicklung'' von dl1ely (Stefan) verfasst wurde. &lt;br /&gt;
&lt;br /&gt;
* Sie finden den Thread hier: [[http://www.contao-community.de/showthread.php?6570-Tagebuch-einer-Extension-Entwicklung Original Forumsbeitrag]]. Dort können Sie die Diskussion weiterführen. Ob künftige Forumsbeiträge hier eingearbeitet werden, ist nicht sichergestellt.&lt;br /&gt;
&lt;br /&gt;
* Die Originalbeiträge wurden redaktionell leicht überarbeitet. Dabei wurden neben forumsspezifischen Besonderheiten auch Überleitungen, Anrede- und Grußformeln, Bewertungen (&amp;quot;Ich finde das Tutorial gaaaanz toll!&amp;quot;) u.ä. entfernt.&lt;br /&gt;
&lt;br /&gt;
* An einigen Stellen wurden kleine Ergänzungen eingefügt.&lt;br /&gt;
&lt;br /&gt;
* Entgegen den Wiki-Gepflogenheiten sind die Artikel in der Ich-Form gehalten, da es sich um einen Erfahrungsbericht handelt.&lt;br /&gt;
&lt;br /&gt;
* Im Großen und Ganzen orientiert sich das Tutorial an der TL/contao-Systematik und besteht daher aus den zwei Blöcken ''Backend'' und ''Frontend''. Eine strikte thematische Gliederung ist hier allerdings nicht möglich. Als Erfahrungsbericht glänzt das Tutorial ja gerade dadurch, dass die im Verlauf der Entwicklung auftretenden Probleme und Fragestellungen abgearbeitet werden und entsprechende Rücksprünge an vorherige, bereits erledigt geglaubte Bearbeitungsschritte erfordern. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Und so ist das Tutorial aufgebaut:&lt;br /&gt;
&lt;br /&gt;
*TEE-00 Vorbemerkungen&lt;br /&gt;
&lt;br /&gt;
*TEE-01 Einleitung&lt;br /&gt;
*TEE-02 Extension Creator&lt;br /&gt;
*TEE-03 Backend BE-Modul und SQL&lt;br /&gt;
*TEE-04 Backend DCA&lt;br /&gt;
*TEE-05 Backend Language Files&lt;br /&gt;
*TEE-06 Backend Callbacks und Subpaletten&lt;br /&gt;
*TEE-07 Frontend Simpel-Version&lt;br /&gt;
*TEE-08 Frontend Parametrisierung&lt;br /&gt;
*TEE-09 Frontend Detailliste&lt;br /&gt;
*TEE-10 Frontend Feinschliff&lt;br /&gt;
*TEE-11 Backend Zweite Tabelle&lt;br /&gt;
*TEE-12 Backend Callbacks&lt;br /&gt;
*TEE-13 Frontend Meldeliste&lt;br /&gt;
*TEE-14 Downloads&lt;br /&gt;
*TEE-15 Werkzeuge&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-15_Werkzeuge</id>
		<title>TEE-15 Werkzeuge</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-15_Werkzeuge"/>
				<updated>2010-07-07T13:35:53Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Werkzeuge=&lt;br /&gt;
==Lokaler Webserver / lokale MySQL-Datenbank==&lt;br /&gt;
Wenn Sie beginnen, sich mit Webdesign zu beschäftigen, werden Sie vermutlich zunächst anfangen, HTML-Seiten auf dem eigenen Rechner zu erstellen und diese in den installierten Browsern zu testen. Dafür reicht zunächst das Dateisystem in Verbindung mit einem Browser aus. &lt;br /&gt;
&lt;br /&gt;
Content Management Systeme (CMS) benötigen aber mehr: die Scriptsprache PHP und mindestens eine MySQL-Datenbank. Und um PHP-Scripte auszuführen, benötigen Sie einen Web-Server: dazu müssten Sie nun jede Datei erst per FTP auf Ihren Webspace hochladen. Das wiederum bedeutet: Sie müssten Zugriff aufs Internet haben.&lt;br /&gt;
&lt;br /&gt;
Um diese Einschränkungen zu umgehen, ist es sinnvoll, sich auf dem eigenen Rechner einen sogenannten lokalen Webserver zu installieren. Das heisst, er befindet sich auf der gleichen Maschine, auf der Sie gerade arbeiten. Dieser lokale Webserver simuliert die Internetumgebung und ermöglicht es Ihnen, Ihre Webseiten so zu betrachten, als stünden sie online im Internet.&lt;br /&gt;
&lt;br /&gt;
Der einzige Unterschied besteht darin, wie man die Seiten aufruft. Bei Aufruf von Seiten im Internet beginnt die Adresse mit &amp;lt;nowiki&amp;gt;http://www.&amp;lt;/nowiki&amp;gt;, beim Aufruf vom lokalen Webserver beginnt sie mit &amp;lt;nowiki&amp;gt;http://127.0.0.1&amp;lt;/nowiki&amp;gt; bzw. &amp;lt;nowiki&amp;gt;http://localhost&amp;lt;/nowiki&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
Die wohl bekannteste Serversoftware, die sich als lokaler Webserver einsetzen lässt, ist der Apache. Diese Software bekommen Sie als Paket zusammen mit den Programmiersprachen PHP und Perl und der Datenbank MySQL.&lt;br /&gt;
&lt;br /&gt;
Eines der bekanntesten Pakete, [http://www.xampp.de/ XAMPP], ist für den Entwickler gedacht, der möglichst schnell ein komplettes und dennoch kompaktes Testsystem aufsetzen möchte. Es ermöglicht das einfache Installieren und Konfigurieren&lt;br /&gt;
* des Webservers Apache,&lt;br /&gt;
* der Datenbank MySQL und &lt;br /&gt;
* der Skriptsprachen PHP und Perl.&lt;br /&gt;
&lt;br /&gt;
Weitere Serversoftware finden Sie hier:&lt;br /&gt;
[http://aktuell.de.selfhtml.org/links/server-software.htm SELFHTML Link-Verzeichnis: Server-Software]&lt;br /&gt;
==Editor==&lt;br /&gt;
===Notepad++===&lt;br /&gt;
Notepad++&lt;br /&gt;
&lt;br /&gt;
===PSPad===&lt;br /&gt;
PSPad ist ein besonders auf Programmierer und Webdesigner zugeschnittener unicode-fähiger Editor für Microsoft Windows mit den folgenden Merkmalen:&lt;br /&gt;
&lt;br /&gt;
* Einfaches Arbeiten mit verschiedenen Entwicklungsumgebungen&lt;br /&gt;
* Farbig hervorgehobene Syntax für viele Programmiersprachen, HTML usw. (erweiterbar)&lt;br /&gt;
* HTML-Vorschau mit einem Tastendruck&lt;br /&gt;
* Geringe Dateigröße, gekoppelt mit dem Funktionsumfang eines professionellen Editors&lt;br /&gt;
* Einfaches Arbeiten mit Textdateien&lt;br /&gt;
&lt;br /&gt;
Näheres siehe unter [http://www.pspad.com/de/ PSPad]&lt;br /&gt;
&lt;br /&gt;
==Bildbearbeitungsprogramm==&lt;br /&gt;
==FTP-Programm==&lt;br /&gt;
FTP ist die Abkürzung für File Transfer Protokoll und bezeichnet eine Übertragungsweise von Dateien über das Internet. Um Dateien von Ihrem lokalen PC auf den Webserver übertragen zu können, benötigen Sie einen FTP-Zugang bei Ihrem Internet-Provider. Zum Aufbau einer FTP-Verbindung benötigen Sie ein FTP-Programm (einen FTP-Client).&lt;br /&gt;
&lt;br /&gt;
===FileZilla===&lt;br /&gt;
FileZilla Client ist ein schneller und zuverlässiger Cross-platform-Client mit grafischer Oberfläche für FTP, FTPS and SFTP.&lt;br /&gt;
&lt;br /&gt;
* Unterstützt FTP, FTP über SSL/TLS (FTPS) und SSH File Transfer Protocol (SFTP)&lt;br /&gt;
* Cross-platform. Läuft unter Windows, Linux, *BSD, Mac OS X and more&lt;br /&gt;
* IPv6-Unterstützung&lt;br /&gt;
* Verfügbar in vielen Sprachen&lt;br /&gt;
* Wiederaufnahme abgebrochener Übertragungen&lt;br /&gt;
* Übertragung großer Dateien &amp;gt;4GB&lt;br /&gt;
* Server-Manager&lt;br /&gt;
* Warteschlangen-Verwaltung&lt;br /&gt;
* Bookmarks&lt;br /&gt;
* Drag &amp;amp; Drop-Unterstützung&lt;br /&gt;
* Konfigurierbare Übertragungsraten&lt;br /&gt;
* Datei- und Verzeichnis-Filter&lt;br /&gt;
* Verzeichnisvergleich&lt;br /&gt;
* Synchronisiertes Browsen lokal/Server&lt;br /&gt;
* Netzwerkkonfigurations-Assistent&lt;br /&gt;
* Keep-alive&lt;br /&gt;
* HTTP/1.1, SOCKS5 und FTP-Proxy-Unterstützung&lt;br /&gt;
* Logging in Datei&lt;br /&gt;
* Remote Dateibearbeitung&lt;br /&gt;
* Remote Dateisuche&lt;br /&gt;
&lt;br /&gt;
Näheres siehe unter [http://filezilla-project.org/index.php FileZilla-Homepage]&lt;br /&gt;
 &lt;br /&gt;
===fireFTP===&lt;br /&gt;
fireFTP ist ein kostenloser FTP-Client für Firefox und wird als AddOn eingebunden.&lt;br /&gt;
 &lt;br /&gt;
Dieser nur wenige KByte kleine FTP-Client unterstützt die Aufnahme von abgebrochenen Downloads. Die Benutzeroberfläche ist einfach und übersichtlich gestaltet, außerdem komplett in deutscher Sprache gehalten.&lt;br /&gt;
&lt;br /&gt;
===WinSCP===&lt;br /&gt;
WinSCP ist ein grafischer Open Source SFTP und FTP Client für Windows, der auch das alte SCP-Protokoll unterstützt. Er bietet einen geschützten Daten- und Dateitransfer zwischen verschiedenen Rechnern und ermöglicht die Nutzung geschützter &amp;quot;Tunnel&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
WinSCP kann alle grundlegenden Operationen mit Dateien, wie downloaden und uploaden, erledigen. Es kann auch Dateien &amp;amp; Ordner umbenennen, neue Ordner erstellen, Eigenschaften von Dateien &amp;amp; Ordnern ändern, und symbolische Links und Verknüpfungen erstellen.&lt;br /&gt;
&lt;br /&gt;
Eine der beiden zur Auswahl stehenden Programm-Oberflächen erlaubt dem Benutzer das Managen von Dateien sogar auf dem lokalen Computer. &lt;br /&gt;
&lt;br /&gt;
Näheres siehe unter [http://winscp.net/eng/docs/lang:de Was ist WinSCP]&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-02_Extension_Creator</id>
		<title>TEE-02 Extension Creator</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-02_Extension_Creator"/>
				<updated>2010-07-07T12:03:20Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Extension-Creator=&lt;br /&gt;
Ich verwende den [http://www.contao.org/erweiterungsliste/view/development.de.html Extension-Creator] aus dem Extension-Repository. Der ''Extension-Creator'', ehemals: ''Module Creator'', wurde von Leo Feyer programmiert, war ursprünglich Teil des TL-Cores und wurde dann in eine separate Extension ausgelagert. Sie müssen den ''Extension-Creator'' also zunächst aus dem Repository installieren. Er firmiert im Repository allerdings nicht als ''Extension-Creator'', sondern als ''development''!&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea01.png]]&lt;br /&gt;
&lt;br /&gt;
Der ''Extension-Creator'' erscheint dann in der Dateistruktur unter ''tl/system/modules/development'' und in der Sidebar des Backends unter ''System''.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea02.png]]&lt;br /&gt;
&lt;br /&gt;
Also, los geht es mit dem Skelett für die geplante Extension.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea03.png]]&lt;br /&gt;
&lt;br /&gt;
* Titel: Es geht um Turnierpaar-&amp;quot;Verwaltung&amp;quot;, und um Namenskonflikte zu vermeiden möchte ich gerne einen spezifischen Präfix nutzen: ''gw'' angelehnt an den Vereinsnamen &amp;quot;Grün-Weiß&amp;quot;. Also: Titel = ''gw_turnierpaare''. An dieser Stelle bin ich mir noch nicht so sicher, wo dieser &amp;quot;Titel&amp;quot; überall erscheinen wird, und ob es deshalb ein beliebiger Text sein soll, oder eher ein &amp;quot;identifier&amp;quot;, also z.b. ohne Leerzeichen u.ä. Sicherheitshalber gehe ich den Identifier-Weg. Besser hässlich als nicht-funktionierend.&lt;br /&gt;
&lt;br /&gt;
* Ordnername: Ebenfalls ''gw_turnierpaare''.&lt;br /&gt;
&lt;br /&gt;
* Autor, Copyright und Lizenz: Selbsterklärend&lt;br /&gt;
&lt;br /&gt;
* Paket: Ein Paketname ist gefragt. Der Hilfetext unter dem Eingabefeld schlägt hilfreich &amp;quot;z.B. meinEigenesModul&amp;quot; vor. Ist das Modul jetzt das Paket? Was ist ein Paket? Sowas wie ein Namensraum? Da ich noch nicht weiß, ob ich für die Vereinsseite noch andere Extensions pogrammieren werde, nehme ich die Vereinsabkürzung als &amp;quot;Paketname&amp;quot;, also ''GW''. Weitere vereinsspezifische Extensions würde ich dann in dasselbe Paket stecken.&lt;br /&gt;
&lt;br /&gt;
* Ein Backend-Modul hinzufügen: Ja klar, schließlich sollen Daten im Backend bearbeitet werden. Also dort ein Häkchen.&lt;br /&gt;
&lt;br /&gt;
* Backend-Klassen: Wenig hilfreicher Erklärungstext: &amp;quot;Hier können Sie eine kommagetrennte Liste der zu erstellenden Backend-Klassen eingeben.&amp;quot; - Was sind Backend-Klassen? Wofür brauche ich die? Eigentlich müsste doch alles, was ich im Backend vorhabe, durch Einträge im DCA-File realisierbar sein, schließlich geht es nur um Pflege von zwei abhängigen Datenbanktabellen. Also mal mutig leer gelassen, falls das falsch ist kann man es später noch hinzufügen.&lt;br /&gt;
&lt;br /&gt;
* Backend-Tabellen: Das sind wohl meine Datentabellen, ich will eine für Turnierpaare, eine für Meldungen, also: ''tl_gw_turnierpaare,tl_gw_meldungen''.&lt;br /&gt;
&lt;br /&gt;
* Backend-Templates: Auch hier wieder wenig erhellender Hilfetext. Auch das TL-Buch beschränkt sich da leider fast auf das Abschreiben der Hilfetexte unter den Eingabefeldern. Ich kenne Templates nur für das Frontend, also beschließe ich mutig, dass ich das wohl nicht brauche. Sollte sich das später als Irrtum herausstellen, wird es sich hoffentlich noch korrigieren lassen.&lt;br /&gt;
&lt;br /&gt;
* Ein Frontend-Modul hinzufügen: Aber klar, die Daten sollen schließlich im Frontend visualisiert werden. Also Haken dran.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Klassen: So weit wie ich es bisher verstanden habe, braucht jedes Modul eine eigene Klasse. Nach meiner bisherigen Planung brauche ich ein Modul ''Turnierpaarliste'' inklusive Detail-Ansicht der einzelnen Paar-Einträge. Die Unterscheidung aktiv/nicht aktiv würde ich gerne über einen Parameter im Modul lösen, so dass dasselbe Modul die Liste der aktiven und der ehemaligen Paare anzeigen kann. Außerdem benötige ich ein Modul ''Meldeliste'' mit der chronologisch sortierten Übersicht der Meldungen. Also: ''gwTurnierpaarliste,gwMeldeliste'' als Klassennnamen.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Tabellen: Ratlosigkeit. Was unterscheidet Frontend-Tabellen von Backend-Tabellen? Da ich meine Tabellen schon in den Backend-Tabellen abgehandelt habe, lasse ich das Feld leer.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Templates: Natürlich! ''gw_turnierpaarliste,gw_turnierpaarliste_detail,gw _meldeliste'' fallen mir sofort ein, vielleicht genügt das schon. Falls nicht, kann ich später noch welche hinzufügen.&lt;br /&gt;
&lt;br /&gt;
* Sprachpakete erstellen: Natürlich. Auch wenn es wahrscheinlich niemand in Englisch benutzen wird, tut es mir aber auch nicht weh, also Sprachen = ''en,de''.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea04.png]]&lt;br /&gt;
&lt;br /&gt;
Dann &amp;quot;speichern und schließen&amp;quot;, und auf den grünen Haken am Ende der neuen Zeile ''gw_turnierpaare'' im Extension-Creator geklickt. &lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea05.png]]&lt;br /&gt;
&lt;br /&gt;
Die Warnung bestätigt, &lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea06.png]]&lt;br /&gt;
&lt;br /&gt;
und der Extension-Creator hat mir erstmal den Grundstock an Files in ''/system/modules/gw_turnierpaare/'' erzeugt. Und zwar:&lt;br /&gt;
&lt;br /&gt;
* ''gwMeldeliste.php,gwTurnierpaarliste.php'': meine Frontendklassen&lt;br /&gt;
&lt;br /&gt;
* ''config/config.php'' und ''config/database.sql'' (Letzteres für meine SQL-Tabellenstruktur)&lt;br /&gt;
&lt;br /&gt;
* ''dca/tl_gw_turnierpaare.php'' und ''dca/tl_gw_meldungen.php'': Die DCA-Definitionen für meine Tabellen zur Bearbeitung im Backend&lt;br /&gt;
&lt;br /&gt;
* ''languages/...'': Die Sprachfiles in en und de-Variante&lt;br /&gt;
&lt;br /&gt;
* ''templates/...'': Die drei Frontend-Templates, die ich angegeben hatte&lt;br /&gt;
&lt;br /&gt;
Im nächsten Schritt orientieren wir uns etwas und beginnen, die vorgegebenen Files zu modifizieren.&lt;br /&gt;
&lt;br /&gt;
P.S.: Wenn die erfahrenen TL-Programmierer jetzt schon Gänsehaut haben: Sorry. Ich mache das zum ersten &lt;br /&gt;
Mal, und stelle mich nicht künstlich dumm an. Ich versuche so zu schildern, wie ich als Einsteiger die Sachen &lt;br /&gt;
sehe, was mich verwirrt usw...Bin für Verbesserungsvorschläge z.B. zu Namens-Schemata usw immer zu haben. &lt;br /&gt;
Genauso freue ich mich über Aufklärung zu Dingen, die ich selbst nicht verstehe...Backendklassen, Backend-&lt;br /&gt;
Templates, Frontend-Tabellen, Paket...&lt;br /&gt;
&lt;br /&gt;
==Diskussion==&lt;br /&gt;
'''user: Schnippsel'''&lt;br /&gt;
&lt;br /&gt;
1. Irritiert bin ich über eine Inkonsistenz Deiner Namenskonvention. Während Du die Mehrzahl der Objekte mit dem Präfix ''gw_'' einleitest, verwendest Du bei den Frontend-Klassen das Präfix ''gw'' (also ohne Unterstrich). Für ein simples Gemüt wie mich würde das unweigerlich zu Fehlern führen. Ich bin da ein Entweder-/Oder-Mensch. Dass die Tabellen durch ein weiteres Präfix (ein Präpräfix?) gekennzeichnet sind, stört und verwirrt mich hingegen überhaupt nicht.&lt;br /&gt;
&lt;br /&gt;
2. Etwas sehr rasant bist Du für mein Empfinden über die Thematik &amp;quot;Autor, Copyright und Lizenz&amp;quot; hinweggehuscht, indem Du sie als &amp;quot;Selbsterklärend&amp;quot; deklariert hast. &lt;br /&gt;
&lt;br /&gt;
Gut: wer der Autor ist, ist tatsächlich meist selbsterklärend, Allerdings würde eine kleine Änderung die Sache noch deutlicher machen, indem man nämlich einfach &amp;quot;Autor(en)&amp;quot; - bei tl_extension.php in den Language Files - schriebe. Da ich selber in vielen Projekten (mit)arbeite, an denen verschiedene Leute am Quellcode arbeiten, ist mir der Hinweis wichtig.&lt;br /&gt;
&lt;br /&gt;
Schwieriger sieht es beim Copyright aus, selbst bei Einzelkämpfern. Wurde der Code z.B. in Rahmen eines normalen Arbeitsverhältnisses erstellt, liegt das Copyright vermutlich nicht beim Autor, sondern bei der Firma (oder dem Verein?), für die er programmiert. Bei Freelancern ist die Frage des Copyrights ggf. abhängig von der Art des Vertrages (Werkvertrag/Dienstvertrag) und/oder entsprechenden vertraglichen Regelungen.&lt;br /&gt;
&lt;br /&gt;
Auch die Frage der Lizenz ist nicht unbedingt trivial, obwohl ich natürlich bei einem &amp;quot;echten&amp;quot; Entwickler (also jemand, der sich beruflich und bezahlt mit derlei Dingen beschäftigt) davon ausgehe, dass er sich über Lizenzfragen im Klaren ist.&lt;br /&gt;
&lt;br /&gt;
Es sei darauf hingewiesen, dass der ''Extension-Creator'' im Kopf der generierten Dateien generell den Text für die GNU/LGPL einträgt, egal was man selbst unter &amp;quot;Lizenz&amp;quot; reinschreibt. Das beruht auf den Templates, die sich unter ''/system/modules/development/templates'' finden. &lt;br /&gt;
&lt;br /&gt;
Für diejenigen, die sich über die GNU/LGPL informieren möchten, hier ein paar Links:&lt;br /&gt;
&lt;br /&gt;
[http://www.gnu.de/documents/lgpl-3.0.de.html GNU Lesser General Public License Version 3.0]&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch:&lt;br /&gt;
&lt;br /&gt;
[http://www.gnu.de/free-software/index.de.html Freie Software]&lt;br /&gt;
&lt;br /&gt;
[http://www.gnu.de/free-software/open-source.de.html Freie Software/Open Source]&lt;br /&gt;
&lt;br /&gt;
3. Mir ist auch der Zusammenhang zwischen Copyright und Lizenz nicht wirklich klar. Ist ''Copyright'' nicht eigentlich auch eine Art ''Lizenz''? Da wäre es schön, wenn ein juristischer Fachmann Licht ins Dunkel bringen könnte - ein Link auf eine verständliche Seite würde mir genügen.&lt;br /&gt;
&lt;br /&gt;
Zu guter Letzt: gibt es nicht auch eine Art ''Vererbung'' der Lizenz? So weit ich es verstanden habe, darf ich in ein Open Source Projekt (Parent) auch nur Open Source Erweiterungen (Child) einbringen.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-02_Extension_Creator</id>
		<title>TEE-02 Extension Creator</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-02_Extension_Creator"/>
				<updated>2010-07-07T11:57:52Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Extension-Creator=&lt;br /&gt;
Ich verwende den [http://www.contao.org/erweiterungsliste/view/development.de.html Extension-Creator] aus dem Extension-Repository. Der ''Extension-Creator'', ehemals: ''Module Creator'', wurde von Leo Feyer programmiert, war ursprünglich Teil des TL-Cores und wurde dann in eine separate Extension ausgelagert. Sie müssen den ''Extension-Creator'' also zunächst aus dem Repository installieren. Er firmiert im Repository allerdings nicht als ''Extension-Creator'', sondern als ''development''!&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea01.png]]&lt;br /&gt;
&lt;br /&gt;
Der ''Extension-Creator'' erscheint dann in der Dateistruktur unter ''tl/system/modules/development'' und in der Sidebar des Backends unter ''System''.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea02.png]]&lt;br /&gt;
&lt;br /&gt;
Also, los geht es mit dem Skelett für die geplante Extension.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea03.png]]&lt;br /&gt;
&lt;br /&gt;
* Titel: Es geht um Turnierpaar-&amp;quot;Verwaltung&amp;quot;, und um Namenskonflikte zu vermeiden möchte ich gerne einen spezifischen Präfix nutzen: ''gw'' angelehnt an den Vereinsnamen &amp;quot;Grün-Weiß&amp;quot;. Also: Titel = ''gw_turnierpaare''. An dieser Stelle bin ich mir noch nicht so sicher, wo dieser &amp;quot;Titel&amp;quot; überall erscheinen wird, und ob es deshalb ein beliebiger Text sein soll, oder eher ein &amp;quot;identifier&amp;quot;, also z.b. ohne Leerzeichen u.ä. Sicherheitshalber gehe ich den Identifier-Weg. Besser hässlich als nicht-funktionierend.&lt;br /&gt;
&lt;br /&gt;
* Ordnername: Ebenfalls ''gw_turnierpaare''.&lt;br /&gt;
&lt;br /&gt;
* Autor, Copyright und Lizenz: Selbsterklärend&lt;br /&gt;
&lt;br /&gt;
* Paket: Ein Paketname ist gefragt. Der Hilfetext unter dem Eingabefeld schlägt hilfreich &amp;quot;z.B. meinEigenesModul&amp;quot; vor. Ist das Modul jetzt das Paket? Was ist ein Paket? Sowas wie ein Namensraum? Da ich noch nicht weiß, ob ich für die Vereinsseite noch andere Extensions pogrammieren werde, nehme ich die Vereinsabkürzung als &amp;quot;Paketname&amp;quot;, also ''GW''. Weitere vereinsspezifische Extensions würde ich dann in dasselbe Paket stecken.&lt;br /&gt;
&lt;br /&gt;
* Ein Backend-Modul hinzufügen: Ja klar, schließlich sollen Daten im Backend bearbeitet werden. Also dort ein Häkchen.&lt;br /&gt;
&lt;br /&gt;
* Backend-Klassen: Wenig hilfreicher Erklärungstext: &amp;quot;Hier können Sie eine kommagetrennte Liste der zu erstellenden Backend-Klassen eingeben.&amp;quot; - Was sind Backend-Klassen? Wofür brauche ich die? Eigentlich müsste doch alles, was ich im Backend vorhabe, durch Einträge im DCA-File realisierbar sein, schließlich geht es nur um Pflege von zwei abhängigen Datenbanktabellen. Also mal mutig leer gelassen, falls das falsch ist kann man es später noch hinzufügen.&lt;br /&gt;
&lt;br /&gt;
* Backend-Tabellen: Das sind wohl meine Datentabellen, ich will eine für Turnierpaare, eine für Meldungen, also: ''tl_gw_turnierpaare,tl_gw_meldungen''.&lt;br /&gt;
&lt;br /&gt;
* Backend-Templates: Auch hier wieder wenig erhellender Hilfetext. Auch das TL-Buch beschränkt sich da leider fast auf das Abschreiben der Hilfetexte unter den Eingabefeldern. Ich kenne Templates nur für das Frontend, also beschließe ich mutig, dass ich das wohl nicht brauche. Sollte sich das später als Irrtum herausstellen, wird es sich hoffentlich noch korrigieren lassen.&lt;br /&gt;
&lt;br /&gt;
* Ein Frontend-Modul hinzufügen: Aber klar, die Daten sollen schließlich im Frontend visualisiert werden. Also Haken dran.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Klassen: So weit wie ich es bisher verstanden habe, braucht jedes Modul eine eigene Klasse. Nach meiner bisherigen Planung brauche ich ein Modul ''Turnierpaarliste'' inklusive Detail-Ansicht der einzelnen Paar-Einträge. Die Unterscheidung aktiv/nicht aktiv würde ich gerne über einen Parameter im Modul lösen, so dass dasselbe Modul die Liste der aktiven und der ehemaligen Paare anzeigen kann. Außerdem benötige ich ein Modul ''Meldeliste'' mit der chronologisch sortierten Übersicht der Meldungen. Also: ''gwTurnierpaarliste,gwMeldeliste'' als Klassennnamen.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Tabellen: Ratlosigkeit. Was unterscheidet Frontend-Tabellen von Backend-Tabellen? Da ich meine Tabellen schon in den Backend-Tabellen abgehandelt habe, lasse ich das Feld leer.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Templates: Natürlich! ''gw_turnierpaarliste,gw_turnierpaarliste_detail,gw _meldeliste'' fallen mir sofort ein, vielleicht genügt das schon. Falls nicht, kann ich später noch welche hinzufügen.&lt;br /&gt;
&lt;br /&gt;
* Sprachpakete erstellen: Natürlich. Auch wenn es wahrscheinlich niemand in Englisch benutzen wird, tut es mir aber auch nicht weh, also Sprachen = ''en,de''.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea04.png]]&lt;br /&gt;
&lt;br /&gt;
Dann &amp;quot;speichern und schließen&amp;quot;, und auf den grünen Haken am Ende der neuen Zeile ''gw_turnierpaare'' im Extension-Creator geklickt. &lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea05.png]]&lt;br /&gt;
&lt;br /&gt;
Die Warnung bestätigt, &lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea06.png]]&lt;br /&gt;
&lt;br /&gt;
und der Extension-Creator hat mir erstmal den Grundstock an Files in ''/system/modules/gw_turnierpaare/'' erzeugt. Und zwar:&lt;br /&gt;
&lt;br /&gt;
* ''gwMeldeliste.php,gwTurnierpaarliste.php'': meine Frontendklassen&lt;br /&gt;
&lt;br /&gt;
* ''config/config.php'' und ''config/database.sql'' (Letzteres für meine SQL-Tabellenstruktur)&lt;br /&gt;
&lt;br /&gt;
* ''dca/tl_gw_turnierpaare.php'' und ''dca/tl_gw_meldungen.php'': Die DCA-Definitionen für meine Tabellen zur Bearbeitung im Backend&lt;br /&gt;
&lt;br /&gt;
* ''languages/...'': Die Sprachfiles in en und de-Variante&lt;br /&gt;
&lt;br /&gt;
* ''templates/...'': Die drei Frontend-Templates, die ich angegeben hatte&lt;br /&gt;
&lt;br /&gt;
Im nächsten Schritt orientieren wir uns etwas und beginnen, die vorgegebenen Files zu modifizieren.&lt;br /&gt;
&lt;br /&gt;
P.S.: Wenn die erfahrenen TL-Programmierer jetzt schon Gänsehaut haben: Sorry. Ich mache das zum ersten &lt;br /&gt;
Mal, und stelle mich nicht künstlich dumm an. Ich versuche so zu schildern, wie ich als Einsteiger die Sachen &lt;br /&gt;
sehe, was mich verwirrt usw...Bin für Verbesserungsvorschläge z.B. zu Namens-Schemata usw immer zu haben. &lt;br /&gt;
Genauso freue ich mich über Aufklärung zu Dingen, die ich selbst nicht verstehe...Backendklassen, Backend-&lt;br /&gt;
Templates, Frontend-Tabellen, Paket...&lt;br /&gt;
&lt;br /&gt;
==Diskussion==&lt;br /&gt;
'''user: Schnippsel'''&lt;br /&gt;
&lt;br /&gt;
1. Irritiert bin ich über eine Inkonsistenz Deiner Namenskonvention. Während Du die Mehrzahl der Objekte mit dem Präfix ''gw_'' einleitest, verwendest Du bei den Frontend-Klassen das Präfix ''gw'' (also ohne Unterstrich). Für ein simples Gemüt wie mich würde das unweigerlich zu Fehlern führen. Ich bin da ein Entweder-/Oder-Mensch. Dass die Tabellen durch ein weiteres Präfix (ein Präpräfix?) gekennzeichnet sind, stört und verwirrt mich hingegen überhaupt nicht.&lt;br /&gt;
&lt;br /&gt;
2. Etwas sehr rasant bist Du für mein Empfinden über die Thematik &amp;quot;Autor, Copyright und Lizenz&amp;quot; hinweggehuscht, indem Du sie als &amp;quot;Selbsterklärend&amp;quot; deklariert hast. &lt;br /&gt;
&lt;br /&gt;
Gut: wer der Autor ist, ist tatsächlich meist selbsterklärend, Allerdings würde eine kleine Änderung die Sache noch deutlicher machen, indem man nämlich einfach &amp;quot;Autor(en)&amp;quot; - bei tl_extension.php in den Language Files - schriebe. Da ich selber in vielen Projekten (mit)arbeite, an denen verschiedene Leute am Quellcode arbeiten, ist mir der Hinweis wichtig.&lt;br /&gt;
&lt;br /&gt;
Schwieriger sieht es beim Copyright aus, selbst bei Einzelkämpfern. Wurde der Code z.B. in Rahmen eines normalen Arbeitsverhältnisses erstellt, liegt das Copyright vermutlich nicht beim Autor, sondern bei der Firma (oder dem Verein?), für die er programmiert. Bei Freelancern ist die Frage des Copyrights ggf. abhängig von der Art des Vertrages (Werkvertrag/Dienstvertrag) und/oder entsprechenden vertraglichen Regelungen.&lt;br /&gt;
&lt;br /&gt;
Auch die Frage der Lizenz ist nicht unbedingt trivial, obwohl ich natürlich bei einem &amp;quot;echten&amp;quot; Entwickler (also jemand, der sich beruflich und bezahlt mit derlei Dingen beschäftigt) davon ausgehe, dass er sich über Lizenzfragen im Klaren ist.&lt;br /&gt;
&lt;br /&gt;
Es sei darauf hingewiesen, dass der ''Extension-Creator'' im Kopf der generierten Dateien generell den Text für die GNU/LGPL einträgt, egal was man selbst unter &amp;quot;Lizenz&amp;quot; reinschreibt. Das beruht auf den Templates, die sich unter ''/system/modules/development/templates'' finden. &lt;br /&gt;
&lt;br /&gt;
Für diejenigen, die sich über die GNU/LGPL informieren möchten, hier ein paar Links:&lt;br /&gt;
&lt;br /&gt;
[http://www.gnu.de/documents/lgpl-3.0.de.html GNU Lesser General Public License Version 3.0]&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch:&lt;br /&gt;
&lt;br /&gt;
[http://www.gnu.de/free-software/index.de.html Freie Software]&lt;br /&gt;
[http://www.gnu.de/free-software/open-source.de.html Freie Software/Open Source]&lt;br /&gt;
&lt;br /&gt;
3. Mir ist auch der Zusammenhang zwischen Copyright und Lizenz nicht wirklich klar. Ist ''Copyright'' nicht eigentlich auch eine Art ''Lizenz''? Da wäre es schön, wenn ein juristischer Fachmann Licht ins Dunkel bringen könnte - ein Link auf eine verständliche Seite würde mir genügen.&lt;br /&gt;
&lt;br /&gt;
Zu guter Letzt: gibt es nicht auch eine Art ''Vererbung'' der Lizenz? So weit ich es verstanden habe, darf ich in ein Open Source Projekt (Parent) auch nur Open Source Erweiterungen (Child) einbringen.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-02_Extension_Creator</id>
		<title>TEE-02 Extension Creator</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-02_Extension_Creator"/>
				<updated>2010-07-07T11:54:27Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Extension-Creator=&lt;br /&gt;
Ich verwende den [http://www.contao.org/erweiterungsliste/view/development.de.html Extension-Creator] aus dem Extension-Repository. Der ''Extension-Creator'', ehemals: ''Module Creator'', wurde von Leo Fey programmiert, war ursprünglich Teil des TL-Cores und wurde dann in eine separate Extension ausgelagert. Sie müssen den ''Extension-Creator'' also zunächst aus dem Repository installieren. Er firmiert im Repository allerdings nicht als ''Extension-Creator'', sondern als ''development''!&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea01.png]]&lt;br /&gt;
&lt;br /&gt;
Der ''Extension-Creator'' erscheint dann in der Dateistruktur unter ''tl/system/modules/development'' und in der Sidebar des Backends unter ''System''.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea02.png]]&lt;br /&gt;
&lt;br /&gt;
Also, los geht es mit dem Skelett für die geplante Extension.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea03.png]]&lt;br /&gt;
&lt;br /&gt;
* Titel: Es geht um Turnierpaar-&amp;quot;Verwaltung&amp;quot;, und um Namenskonflikte zu vermeiden möchte ich gerne einen spezifischen Präfix nutzen: ''gw'' angelehnt an den Vereinsnamen &amp;quot;Grün-Weiß&amp;quot;. Also: Titel = ''gw_turnierpaare''. An dieser Stelle bin ich mir noch nicht so sicher, wo dieser &amp;quot;Titel&amp;quot; überall erscheinen wird, und ob es deshalb ein beliebiger Text sein soll, oder eher ein &amp;quot;identifier&amp;quot;, also z.b. ohne Leerzeichen u.ä. Sicherheitshalber gehe ich den Identifier-Weg. Besser hässlich als nicht-funktionierend.&lt;br /&gt;
&lt;br /&gt;
* Ordnername: Ebenfalls ''gw_turnierpaare''.&lt;br /&gt;
&lt;br /&gt;
* Autor, Copyright und Lizenz: Selbsterklärend&lt;br /&gt;
&lt;br /&gt;
* Paket: Ein Paketname ist gefragt. Der Hilfetext unter dem Eingabefeld schlägt hilfreich &amp;quot;z.B. meinEigenesModul&amp;quot; vor. Ist das Modul jetzt das Paket? Was ist ein Paket? Sowas wie ein Namensraum? Da ich noch nicht weiß, ob ich für die Vereinsseite noch andere Extensions pogrammieren werde, nehme ich die Vereinsabkürzung als &amp;quot;Paketname&amp;quot;, also ''GW''. Weitere vereinsspezifische Extensions würde ich dann in dasselbe Paket stecken.&lt;br /&gt;
&lt;br /&gt;
* Ein Backend-Modul hinzufügen: Ja klar, schließlich sollen Daten im Backend bearbeitet werden. Also dort ein Häkchen.&lt;br /&gt;
&lt;br /&gt;
* Backend-Klassen: Wenig hilfreicher Erklärungstext: &amp;quot;Hier können Sie eine kommagetrennte Liste der zu erstellenden Backend-Klassen eingeben.&amp;quot; - Was sind Backend-Klassen? Wofür brauche ich die? Eigentlich müsste doch alles, was ich im Backend vorhabe, durch Einträge im DCA-File realisierbar sein, schließlich geht es nur um Pflege von zwei abhängigen Datenbanktabellen. Also mal mutig leer gelassen, falls das falsch ist kann man es später noch hinzufügen.&lt;br /&gt;
&lt;br /&gt;
* Backend-Tabellen: Das sind wohl meine Datentabellen, ich will eine für Turnierpaare, eine für Meldungen, also: ''tl_gw_turnierpaare,tl_gw_meldungen''.&lt;br /&gt;
&lt;br /&gt;
* Backend-Templates: Auch hier wieder wenig erhellender Hilfetext. Auch das TL-Buch beschränkt sich da leider fast auf das Abschreiben der Hilfetexte unter den Eingabefeldern. Ich kenne Templates nur für das Frontend, also beschließe ich mutig, dass ich das wohl nicht brauche. Sollte sich das später als Irrtum herausstellen, wird es sich hoffentlich noch korrigieren lassen.&lt;br /&gt;
&lt;br /&gt;
* Ein Frontend-Modul hinzufügen: Aber klar, die Daten sollen schließlich im Frontend visualisiert werden. Also Haken dran.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Klassen: So weit wie ich es bisher verstanden habe, braucht jedes Modul eine eigene Klasse. Nach meiner bisherigen Planung brauche ich ein Modul ''Turnierpaarliste'' inklusive Detail-Ansicht der einzelnen Paar-Einträge. Die Unterscheidung aktiv/nicht aktiv würde ich gerne über einen Parameter im Modul lösen, so dass dasselbe Modul die Liste der aktiven und der ehemaligen Paare anzeigen kann. Außerdem benötige ich ein Modul ''Meldeliste'' mit der chronologisch sortierten Übersicht der Meldungen. Also: ''gwTurnierpaarliste,gwMeldeliste'' als Klassennnamen.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Tabellen: Ratlosigkeit. Was unterscheidet Frontend-Tabellen von Backend-Tabellen? Da ich meine Tabellen schon in den Backend-Tabellen abgehandelt habe, lasse ich das Feld leer.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Templates: Natürlich! ''gw_turnierpaarliste,gw_turnierpaarliste_detail,gw _meldeliste'' fallen mir sofort ein, vielleicht genügt das schon. Falls nicht, kann ich später noch welche hinzufügen.&lt;br /&gt;
&lt;br /&gt;
* Sprachpakete erstellen: Natürlich. Auch wenn es wahrscheinlich niemand in Englisch benutzen wird, tut es mir aber auch nicht weh, also Sprachen = ''en,de''.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea04.png]]&lt;br /&gt;
&lt;br /&gt;
Dann &amp;quot;speichern und schließen&amp;quot;, und auf den grünen Haken am Ende der neuen Zeile ''gw_turnierpaare'' im Extension-Creator geklickt. &lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea05.png]]&lt;br /&gt;
&lt;br /&gt;
Die Warnung bestätigt, &lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea06.png]]&lt;br /&gt;
&lt;br /&gt;
und der Extension-Creator hat mir erstmal den Grundstock an Files in ''/system/modules/gw_turnierpaare/'' erzeugt. Und zwar:&lt;br /&gt;
&lt;br /&gt;
* ''gwMeldeliste.php,gwTurnierpaarliste.php'': meine Frontendklassen&lt;br /&gt;
&lt;br /&gt;
* ''config/config.php'' und ''config/database.sql'' (Letzteres für meine SQL-Tabellenstruktur)&lt;br /&gt;
&lt;br /&gt;
* ''dca/tl_gw_turnierpaare.php'' und ''dca/tl_gw_meldungen.php'': Die DCA-Definitionen für meine Tabellen zur Bearbeitung im Backend&lt;br /&gt;
&lt;br /&gt;
* ''languages/...'': Die Sprachfiles in en und de-Variante&lt;br /&gt;
&lt;br /&gt;
* ''templates/...'': Die drei Frontend-Templates, die ich angegeben hatte&lt;br /&gt;
&lt;br /&gt;
Im nächsten Schritt orientieren wir uns etwas und beginnen, die vorgegebenen Files zu modifizieren.&lt;br /&gt;
&lt;br /&gt;
P.S.: Wenn die erfahrenen TL-Programmierer jetzt schon Gänsehaut haben: Sorry. Ich mache das zum ersten &lt;br /&gt;
Mal, und stelle mich nicht künstlich dumm an. Ich versuche so zu schildern, wie ich als Einsteiger die Sachen &lt;br /&gt;
sehe, was mich verwirrt usw...Bin für Verbesserungsvorschläge z.B. zu Namens-Schemata usw immer zu haben. &lt;br /&gt;
Genauso freue ich mich über Aufklärung zu Dingen, die ich selbst nicht verstehe...Backendklassen, Backend-&lt;br /&gt;
Templates, Frontend-Tabellen, Paket...&lt;br /&gt;
&lt;br /&gt;
==Diskussion==&lt;br /&gt;
'''user: Schnippsel'''&lt;br /&gt;
&lt;br /&gt;
1. Irritiert bin ich über eine Inkonsistenz Deiner Namenskonvention. Während Du die Mehrzahl der Objekte mit dem Präfix ''gw_'' einleitest, verwendest Du bei den Frontend-Klassen das Präfix ''gw'' (also ohne Unterstrich). Für ein simples Gemüt wie mich würde das unweigerlich zu Fehlern führen. Ich bin da ein Entweder-/Oder-Mensch. Dass die Tabellen durch ein weiteres Präfix (ein Präpräfix?) gekennzeichnet sind, stört und verwirrt mich hingegen überhaupt nicht.&lt;br /&gt;
&lt;br /&gt;
2. Etwas sehr rasant bist Du für mein Empfinden über die Thematik &amp;quot;Autor, Copyright und Lizenz&amp;quot; hinweggehuscht, indem Du sie als &amp;quot;Selbsterklärend&amp;quot; deklariert hast. &lt;br /&gt;
&lt;br /&gt;
Gut: wer der Autor ist, ist tatsächlich meist selbsterklärend, Allerdings würde eine kleine Änderung die Sache noch deutlicher machen, indem man nämlich einfach &amp;quot;Autor(en)&amp;quot; - bei tl_extension.php in den Language Files - schriebe. Da ich selber in vielen Projekten (mit)arbeite, an denen verschiedene Leute am Quellcode arbeiten, ist mir der Hinweis wichtig.&lt;br /&gt;
&lt;br /&gt;
Schwieriger sieht es beim Copyright aus, selbst bei Einzelkämpfern. Wurde der Code z.B. in Rahmen eines normalen Arbeitsverhältnisses erstellt, liegt das Copyright vermutlich nicht beim Autor, sondern bei der Firma (oder dem Verein?), für die er programmiert. Bei Freelancern ist die Frage des Copyrights ggf. abhängig von der Art des Vertrages (Werkvertrag/Dienstvertrag) und/oder entsprechenden vertraglichen Regelungen.&lt;br /&gt;
&lt;br /&gt;
Auch die Frage der Lizenz ist nicht unbedingt trivial, obwohl ich natürlich bei einem &amp;quot;echten&amp;quot; Entwickler (also jemand, der sich beruflich und bezahlt mit derlei Dingen beschäftigt) davon ausgehe, dass er sich über Lizenzfragen im Klaren ist.&lt;br /&gt;
&lt;br /&gt;
Es sei darauf hingewiesen, dass der ''Extension-Creator'' im Kopf der generierten Dateien generell den Text für die GNU/LGPL einträgt, egal was man selbst unter &amp;quot;Lizenz&amp;quot; reinschreibt. Das beruht auf den Templates, die sich unter ''/system/modules/development/templates'' finden. &lt;br /&gt;
&lt;br /&gt;
Für diejenigen, die sich über die GNU/LGPL informieren möchten, hier ein paar Links:&lt;br /&gt;
&lt;br /&gt;
[http://www.gnu.de/documents/lgpl-3.0.de.html GNU Lesser General Public License Version 3.0]&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch:&lt;br /&gt;
&lt;br /&gt;
[http://www.gnu.de/free-software/index.de.html Freie Software]&lt;br /&gt;
[http://www.gnu.de/free-software/open-source.de.html Freie Software/Open Source]&lt;br /&gt;
&lt;br /&gt;
3. Mir ist auch der Zusammenhang zwischen Copyright und Lizenz nicht wirklich klar. Ist ''Copyright'' nicht eigentlich auch eine Art ''Lizenz''? Da wäre es schön, wenn ein juristischer Fachmann Licht ins Dunkel bringen könnte - ein Link auf eine verständliche Seite würde mir genügen.&lt;br /&gt;
&lt;br /&gt;
Zu guter Letzt: gibt es nicht auch eine Art ''Vererbung'' der Lizenz? So weit ich es verstanden habe, darf ich in ein Open Source Projekt (Parent) auch nur Open Source Erweiterungen (Child) einbringen.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-02_Extension_Creator</id>
		<title>TEE-02 Extension Creator</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-02_Extension_Creator"/>
				<updated>2010-07-07T11:34:07Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Extension-Creator=&lt;br /&gt;
Ich verwende den [http://www.contao.org/erweiterungsliste/view/development.de.html Extension-Creator] aus dem Extension-Repository. Der ''Extension-Creator'', ehemals: ''Module Creator'', wurde von Leo Fey programmiert, war ursprünglich Teil des TL-Cores und wurde dann in eine separate Extension ausgelagert. Sie müssen den ''Extension-Creator'' also zunächst aus dem Repository installieren. Er firmiert im Repository allerdings nicht als ''Extension-Creator'', sondern als ''development''!&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea01.png]]&lt;br /&gt;
&lt;br /&gt;
Der ''Extension-Creator'' erscheint dann in der Dateistruktur unter ''tl/system/modules/development'' und in der Sidebar des Backends unter ''System''.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea02.png]]&lt;br /&gt;
&lt;br /&gt;
Also, los geht es mit dem Skelett für die geplante Extension.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea03.png]]&lt;br /&gt;
&lt;br /&gt;
* Titel: Es geht um Turnierpaar-&amp;quot;Verwaltung&amp;quot;, und um Namenskonflikte zu vermeiden möchte ich gerne einen spezifischen Präfix nutzen: ''gw'' angelehnt an den Vereinsnamen &amp;quot;Grün-Weiß&amp;quot;. Also: Titel = ''gw_turnierpaare''. An dieser Stelle bin ich mir noch nicht so sicher, wo dieser &amp;quot;Titel&amp;quot; überall erscheinen wird, und ob es deshalb ein beliebiger Text sein soll, oder eher ein &amp;quot;identifier&amp;quot;, also z.b. ohne Leerzeichen u.ä. Sicherheitshalber gehe ich den Identifier-Weg. Besser hässlich als nicht-funktionierend.&lt;br /&gt;
&lt;br /&gt;
* Ordnername: Ebenfalls ''gw_turnierpaare''.&lt;br /&gt;
&lt;br /&gt;
* Autor, Copyright und Lizenz: Selbsterklärend&lt;br /&gt;
&lt;br /&gt;
* Paket: Ein Paketname ist gefragt. Der Hilfetext unter dem Eingabefeld schlägt hilfreich &amp;quot;z.B. meinEigenesModul&amp;quot; vor. Ist das Modul jetzt das Paket? Was ist ein Paket? Sowas wie ein Namensraum? Da ich noch nicht weiß, ob ich für die Vereinsseite noch andere Extensions pogrammieren werde, nehme ich die Vereinsabkürzung als &amp;quot;Paketname&amp;quot;, also ''GW''. Weitere vereinsspezifische Extensions würde ich dann in dasselbe Paket stecken.&lt;br /&gt;
&lt;br /&gt;
* Ein Backend-Modul hinzufügen: Ja klar, schließlich sollen Daten im Backend bearbeitet werden. Also dort ein Häkchen.&lt;br /&gt;
&lt;br /&gt;
* Backend-Klassen: Wenig hilfreicher Erklärungstext: &amp;quot;Hier können Sie eine kommagetrennte Liste der zu erstellenden Backend-Klassen eingeben.&amp;quot; - Was sind Backend-Klassen? Wofür brauche ich die? Eigentlich müsste doch alles, was ich im Backend vorhabe, durch Einträge im DCA-File realisierbar sein, schließlich geht es nur um Pflege von zwei abhängigen Datenbanktabellen. Also mal mutig leer gelassen, falls das falsch ist kann man es später noch hinzufügen.&lt;br /&gt;
&lt;br /&gt;
* Backend-Tabellen: Das sind wohl meine Datentabellen, ich will eine für Turnierpaare, eine für Meldungen, also: ''tl_gw_turnierpaare,tl_gw_meldungen''.&lt;br /&gt;
&lt;br /&gt;
* Backend-Templates: Auch hier wieder wenig erhellender Hilfetext. Auch das TL-Buch beschränkt sich da leider fast auf das Abschreiben der Hilfetexte unter den Eingabefeldern. Ich kenne Templates nur für das Frontend, also beschließe ich mutig, dass ich das wohl nicht brauche. Sollte sich das später als Irrtum herausstellen, wird es sich hoffentlich noch korrigieren lassen.&lt;br /&gt;
&lt;br /&gt;
* Ein Frontend-Modul hinzufügen: Aber klar, die Daten sollen schließlich im Frontend visualisiert werden. Also Haken dran.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Klassen: So weit wie ich es bisher verstanden habe, braucht jedes Modul eine eigene Klasse. Nach meiner bisherigen Planung brauche ich ein Modul ''Turnierpaarliste'' inklusive Detail-Ansicht der einzelnen Paar-Einträge. Die Unterscheidung aktiv/nicht aktiv würde ich gerne über einen Parameter im Modul lösen, so dass dasselbe Modul die Liste der aktiven und der ehemaligen Paare anzeigen kann. Außerdem benötige ich ein Modul ''Meldeliste'' mit der chronologisch sortierten Übersicht der Meldungen. Also: ''gwTurnierpaarliste,gwMeldeliste'' als Klassennnamen.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Tabellen: Ratlosigkeit. Was unterscheidet Frontend-Tabellen von Backend-Tabellen? Da ich meine Tabellen schon in den Backend-Tabellen abgehandelt habe, lasse ich das Feld leer.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Templates: Natürlich! ''gw_turnierpaarliste,gw_turnierpaarliste_detail,gw _meldeliste'' fallen mir sofort ein, vielleicht genügt das schon. Falls nicht, kann ich später noch welche hinzufügen.&lt;br /&gt;
&lt;br /&gt;
* Sprachpakete erstellen: Natürlich. Auch wenn es wahrscheinlich niemand in Englisch benutzen wird, tut es mir aber auch nicht weh, also Sprachen = ''en,de''.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea04.png]]&lt;br /&gt;
&lt;br /&gt;
Dann &amp;quot;speichern und schließen&amp;quot;, und auf den grünen Haken am Ende der neuen Zeile ''gw_turnierpaare'' im Extension-Creator geklickt. &lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea05.png]]&lt;br /&gt;
&lt;br /&gt;
Die Warnung bestätigt, &lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea06.png]]&lt;br /&gt;
&lt;br /&gt;
und der Extension-Creator hat mir erstmal den Grundstock an Files in ''/system/modules/gw_turnierpaare/'' erzeugt. Und zwar:&lt;br /&gt;
&lt;br /&gt;
* ''gwMeldeliste.php,gwTurnierpaarliste.php'': meine Frontendklassen&lt;br /&gt;
&lt;br /&gt;
* ''config/config.php'' und ''config/database.sql'' (Letzteres für meine SQL-Tabellenstruktur)&lt;br /&gt;
&lt;br /&gt;
* ''dca/tl_gw_turnierpaare.php'' und ''dca/tl_gw_meldungen.php'': Die DCA-Definitionen für meine Tabellen zur Bearbeitung im Backend&lt;br /&gt;
&lt;br /&gt;
* ''languages/...'': Die Sprachfiles in en und de-Variante&lt;br /&gt;
&lt;br /&gt;
* ''templates/...'': Die drei Frontend-Templates, die ich angegeben hatte&lt;br /&gt;
&lt;br /&gt;
Im nächsten Schritt orientieren wir uns etwas und beginnen, die vorgegebenen Files zu modifizieren.&lt;br /&gt;
&lt;br /&gt;
P.S.: Wenn die erfahrenen TL-Programmierer jetzt schon Gänsehaut haben: Sorry. Ich mache das zum ersten &lt;br /&gt;
Mal, und stelle mich nicht künstlich dumm an. Ich versuche so zu schildern, wie ich als Einsteiger die Sachen &lt;br /&gt;
sehe, was mich verwirrt usw...Bin für Verbesserungsvorschläge z.B. zu Namens-Schemata usw immer zu haben. &lt;br /&gt;
Genauso freue ich mich über Aufklärung zu Dingen, die ich selbst nicht verstehe...Backendklassen, Backend-&lt;br /&gt;
Templates, Frontend-Tabellen, Paket...&lt;br /&gt;
&lt;br /&gt;
==Diskussion==&lt;br /&gt;
'''user: Schnippsel'''&lt;br /&gt;
&lt;br /&gt;
1. Irritiert bin ich über eine Inkonsistenz Deiner Namenskonvention. Während Du die Mehrzahl der Objekte mit dem Präfix ''gw_'' einleitest, verwendest Du bei den Frontend-Klassen das Präfix ''gw'' (also ohne Unterstrich). Für ein simples Gemüt wie mich würde das unweigerlich zu Fehlern führen. Ich bin da ein Entweder-/Oder-Mensch. Dass die Tabellen durch ein weiteres Präfix (ein Präpräfix?) gekennzeichnet sind, stört und verwirrt mich hingegen überhaupt nicht.&lt;br /&gt;
&lt;br /&gt;
2. Etwas sehr rasant bist Du für mein Empfinden über die Thematik &amp;quot;Autor, Copyright und Lizenz&amp;quot; hinweggehuscht, indem Du sie als &amp;quot;Selbsterklärend&amp;quot; deklariert hast. &lt;br /&gt;
&lt;br /&gt;
Gut: wer der Autor ist, ist tatsächlich meist selbsterklärend, Allerdings würde eine kleine Änderung die Sache noch deutlicher machen, indem man nämlich einfach &amp;quot;Autor(en)&amp;quot; schriebe. Da ich selber in vielen Projekten (mit)arbeite, an denen verschiedene Leute am Quellcode arbeiten, ist mir der Hinweis wichtig.&lt;br /&gt;
&lt;br /&gt;
Schwieriger sieht es beim Copyright aus, selbst bei Einzelkämpfern. Wurde der Code z.B. in Rahmen eines normalen Arbeitsverhältnisses erstellt, liegt das Copyright vermutlich nicht beim Autor, sondern bei der Firma (oder dem Verein?), für die er programmiert. Bei Freelancern ist die Frage des Copyrights ggf. abhängig von der Art des Vertrages (Werkvertrag/Dienstvertrag) und/oder entsprechenden vertraglichen Regelungen.&lt;br /&gt;
&lt;br /&gt;
Auch die Frage der Lizenz ist nicht unbedingt trivial, obwohl ich natürlich bei einem &amp;quot;echten&amp;quot; Entwickler (also jemand, der sich beruflich und bezahlt mit derlei Dingen beschäftigt) davon ausgehe, dass er sich über Lizenzfragen im Klaren ist.&lt;br /&gt;
&lt;br /&gt;
Es sei darauf hingewiesen, dass der ''Extension-Creator'' im Kopf der generierten Dateien generell den Text für die GNU/LGPL einträgt, egal was man selbst unter &amp;quot;Lizenz&amp;quot; reinschreibt. Das beruht auf den Templates, die sich unter ''/system/modules/development/templates'' finden. &lt;br /&gt;
&lt;br /&gt;
Für diejenigen, die sich über die GNU/LGPL informieren möchten, hier ein paar Links:&lt;br /&gt;
&lt;br /&gt;
[http://www.gnu.de/documents/lgpl-3.0.de.html GNU Lesser General Public License Version 3.0]&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch:&lt;br /&gt;
&lt;br /&gt;
[http://www.gnu.de/free-software/index.de.html Freie Software]&lt;br /&gt;
[http://www.gnu.de/free-software/open-source.de.html Freie Software/Open Source]&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-06_Backend_Callbacks_und_Subpaletten</id>
		<title>TEE-06 Backend Callbacks und Subpaletten</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-06_Backend_Callbacks_und_Subpaletten"/>
				<updated>2010-07-07T10:45:09Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Von C…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Von Callbacks und Subpaletten=&lt;br /&gt;
Nachdem auch das englische Sprachfile fertig ist, geht es nun an die letzte fehlende Funktionalität der Backend-Maske. Zunächst gibt es aber noch einige Detailkorrekturen.&lt;br /&gt;
&lt;br /&gt;
Da MySQL keinen ''Boolean''-Datentyp bietet, hatte ich die Felder, die nur true/false sein können, als int(1) angelegt, mit den möglichen Werten 0/1. Das klappt auch prinzipiell, die Stati der Checkboxen werden gespeichert und wieder aus der Datenbank ausgelesen, aber ein Problem zeigt sich, wenn man nach so einem Feld filtern will: Ich will nach dem ''aktiv''-Feld filtern können. Häufig sind die die &amp;quot;aktiven&amp;quot; Turnierpaare von Interesse, die nicht mehr aktiven verstopfen aber die Liste.&lt;br /&gt;
&lt;br /&gt;
Wählt man dieses Feld nun als Filter-Feld aus, werden in der DropDown-Liste als Filtermöglichkeiten aber nur &amp;quot;Ja&amp;quot; und nochmals &amp;quot;Ja&amp;quot; angezeigt. Das Filtern klappt damit auch, bei dem einen &amp;quot;Ja&amp;quot; werden nur die aktiven Paare angezeigt, beim anderen &amp;quot;Ja&amp;quot; die inaktiven. Aber das ist natürlich nicht so gewollt.&lt;br /&gt;
&lt;br /&gt;
Durch Abschauen bei anderen Extensions bin ich darauf gekommen, die Checkbox-Felder durch ''char(1)'' statt ''int(1)'' abzubilden. Das klappt genau so gut, und auch das Filtern funktioniert mit &amp;quot;Ja&amp;quot; und &amp;quot;Nein&amp;quot;. Alle ''int(1)''-Felder wurden entsprechend in ''char(1)'' verändert. Nach dem Anpassen der ''database.sql'' muss natürlich das Install-Tool ausgeführt werden, um die Änderungen in der Datenbank durchzuführen.&lt;br /&gt;
&lt;br /&gt;
Die ''database.sql'' sieht jetzt so aus:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE `tl_gw_turnierpaare` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `partnernachname` varchar(64) NOT NULL default '',&lt;br /&gt;
  `partnervorname` varchar(64) NULL default NULL,&lt;br /&gt;
  `partnerinnachname` varchar(64) NULL default NULL,&lt;br /&gt;
  `partnerinvorname` varchar(64) NULL default NULL,&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '',&lt;br /&gt;
  `startklasselatein` varchar(12) NULL default NULL,&lt;br /&gt;
  `startklassestandard` varchar(12) NULL default NULL,&lt;br /&gt;
  `aktiv` char(1) NOT NULL default '',&lt;br /&gt;
  `aktivseit` int(4) NULL default NULL,&lt;br /&gt;
  `aktivbis` int(4) NULL default NULL,&lt;br /&gt;
  `resetpassword` char(1) NULL default '',&lt;br /&gt;
  `password` varchar(64) NULL default NULL,&lt;br /&gt;
  `bild` varchar(255) NULL default NULL,&lt;br /&gt;
  `anschrift` text NULL,&lt;br /&gt;
  `zeigeanschrift` char(1) NOT NULL default '',&lt;br /&gt;
  `telefon` varchar(32) NULL default NULL,&lt;br /&gt;
  `zeigetelefon` char(1) NOT NULL default '',&lt;br /&gt;
  `fax` varchar(32) NULL default NULL,&lt;br /&gt;
  `zeigefax` char(1) NOT NULL default '',&lt;br /&gt;
  `mobil` varchar(32) NULL default NULL,&lt;br /&gt;
  `zeigemobil` char(1) NOT NULL default '',&lt;br /&gt;
  `email` varchar(128) NULL default NULL,&lt;br /&gt;
  `zeigeemail` char(1) NOT NULL default '',&lt;br /&gt;
  `homepage` varchar(128) NULL default NULL,&lt;br /&gt;
  `zeigehomepage` char(1) NOT NULL default '',&lt;br /&gt;
  `beschreibung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer aufgepasst hat, dem ist auch noch ein neues Feld aufgefallen:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  `resetpassword` char(1) NULL default '',&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das werde ich gleich für das Aktivieren einer Subpalette benötigen. Der Inhalt des Feldes in der Datenbank wird später nicht gebraucht, aber leider muss das Feld vorhanden sein, um es so nutzen zu können, wie ich es vorhabe.&lt;br /&gt;
&lt;br /&gt;
Für das ''password''-Feld habe ich ich vor, dass ein dort eingegebenes Passwort SHA1-gehasht in der Datenbank abgelegt wird, nicht im Klartext. Dabei wird ein eventuell schon vorhandes Passwort natürlich überschrieben.&lt;br /&gt;
&lt;br /&gt;
Um Fehleingaben zu verhindern, möchte ich eine Checkbox anzeigen, die defaultmäßig &amp;quot;aus&amp;quot; ist. Erst wenn die Checkbox aktiviert ist, soll per AJAX das Passwortfeld angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Zunächst fügen die wir Definition für das Checkbox-Feld in die ''field''-Sektion des DCA-Records ein:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'resetpassword' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['resetpassword'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'default'                 =&amp;gt; '', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true, 'submitOnChange' =&amp;gt; true), &lt;br /&gt;
        ), &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''submitOnChange'' bewirkt, dass das Formular neu geladen wird, wenn das Feld angeklickt wird. nur dann wird das Passwortfeld nachgeladen.&lt;br /&gt;
&lt;br /&gt;
Dafür benötigen wir eine sogenannte &amp;quot;Subpalette&amp;quot;. Die Checkbox (bei mir &amp;quot;resetpassword&amp;quot;) muss als &amp;quot;__selector__&amp;quot; angegeben werden im DCA-Record:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array('resetpassword'), &lt;br /&gt;
...  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der ''default''-Sektion sieht die Palettendefinition so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
                                  .'{aktiv_legend:hide},aktiv,aktivseit,aktivbis;{password_legend:hide},resetpassword;'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier steht also der Name der Subpalette. Der Name des Passwortfeldes steht hier nicht mehr. Das wird in der ''subpalettes''-Sektion angegeben:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Subpalettes &lt;br /&gt;
    'subpalettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'resetpassword'               =&amp;gt; 'password' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies bedeutet, dass das Feld ''password'' in die Subpalette ''resetpassword'' eingeblendet wird, wenn ''resetpassword'' aktiviert ist. Wird es deaktiviert, verschwindet die Subpalette wieder.    &lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_016.png]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_017.png]]&lt;br /&gt;
&lt;br /&gt;
Die Texte hierzu wurden in den Sprachfiles entsprechend erweitert und angepasst.&lt;br /&gt;
&lt;br /&gt;
Für beide Felder, ''resetpassword'' und ''password'', benötige ich besondere Funktionalitäten. ''resetpassword'' soll bei Öffnen der Backendmaske IMMER deaktiviert, das Passwort-Feld also versteckt sein - egal was in der Datenbank für das Feld steht. Dafür setze ich zunächst&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'default'                 =&amp;gt; '',  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
was dafür sorgt, dass beim Anlegen eines neuen Datensatzes die Checkbox deaktiviert ist. Und dann gibt es noch die Option ''load_callback'', in der eine Funktion angegeben werden kann, die beim Laden des Feldes aufgerufen wird (Zu den Details von Callbacks gleich mehr).&lt;br /&gt;
&lt;br /&gt;
Hier habe ich versucht, durch ''return &amp;lt;nowiki&amp;gt;' '&amp;lt;/nowiki&amp;gt;;'' immer den Defaultwert zurückzugeben. Leider klappt das nicht richtig, wenn der Datensatz mit &amp;quot;speichern&amp;quot; gespeichert wird, aber geöffnet bleibt. Obwohl die Checkbox dann deaktiviert dargestellt wird, bleibt das Passwort-Feld trotzdem angezeigt und wird nicht versteckt. Erst durch manuelles Aktivieren und erneutes Deaktivieren verschwindet das Passwortfeld wieder. Ich weiß nicht, ob das ein Bug oder gewollt ist, zumindest gefiel es mir nicht.&lt;br /&gt;
&lt;br /&gt;
Ein weiterer Versuch scheiterte mit dem ''save_callback'': also einer Funktion, die aufgerufen wird, bevor das Feld in die Datenbank gespeichert wird. Hier versuchte ich ebenfalls durch ein ''return &amp;lt;nowiki&amp;gt;' '&amp;lt;/nowiki&amp;gt;;'' zu erzwingen, dass immer ein deaktiviertes Feld gespeichert wird, und damit auch beim erneuten Anzeigen des Formulars deaktiviert bleibt.&lt;br /&gt;
&lt;br /&gt;
Das funktioniert optisch auch sehr gut. Leider werden dann aber keine Eingaben im Passwort-Feld gespeichert.&lt;br /&gt;
&lt;br /&gt;
Der Grund wird sehr wahrscheinlich sein, dass der ''save_callback'' auf dem ''resetpassword''-Feld ausgeführt wird, bevor der Input im ''password''-Feld verarbeitet wird. Mein ''Save-Callback'' deaktiviert die Checkbox, und damit auch die Subpalette, und das Feld in der Subpalette wird gar nicht mehr ausgewertet oder gespeichert. Auch die Reihenfolge der Felddefinitionen hat darauf keinen Einfluss, es kommt wohl auf die Reihenfolge in der Palettendefinition an, und die kann ich nicht umdrehen.&lt;br /&gt;
&lt;br /&gt;
An der Stelle war tiefe Frustration angesagt, aber ich habe das Problem anders lösen können. Beim ''resetpassword''-Feld werden jetzt keine Callbacks verwendet.&lt;br /&gt;
&lt;br /&gt;
Dafür aber beim ''password''-Feld, was jetzt in der Definition so aussieht:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'password' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['password'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength' =&amp;gt; 64), &lt;br /&gt;
            'load_callback'           =&amp;gt; array(array('tl_gw_turnierpaare','password_load_callback')), &lt;br /&gt;
            'save_callback'           =&amp;gt; array(array('tl_gw_turnierpaare','password_save_callback')) &lt;br /&gt;
        ), &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Durch diese Definition wird beim Laden des Feldes die Funktion ''password_load_callback'' und beim Speichern ''password_save_callback'' aufgerufen, die sich in der Klasse ''tl_gw_turnierpaare'' befinden. Diese Klasse lege ich in der DCA-Definitions-Datei ''/modules/gw_turnierpaare/dca/tl_gw_turnierpaare.php'' an.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class tl_gw_turnierpaare extends Backend &lt;br /&gt;
{ &lt;br /&gt;
    /** &lt;br /&gt;
     * Import the back end user object &lt;br /&gt;
     */ &lt;br /&gt;
    public function __construct() &lt;br /&gt;
    { &lt;br /&gt;
        parent::__construct(); &lt;br /&gt;
        $this-&amp;gt;import('BackendUser', 'User'); &lt;br /&gt;
    } &lt;br /&gt;
   &lt;br /&gt;
  public function password_load_callback() &lt;br /&gt;
  { &lt;br /&gt;
 ... &lt;br /&gt;
 } &lt;br /&gt;
   &lt;br /&gt;
  public function password_save_callback($var, $dc) &lt;br /&gt;
  { &lt;br /&gt;
... &lt;br /&gt;
  } &lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Gerüst habe ich mir bei anderen Extensions abgeschaut, es scheint zumindest klug zu sein, von ''Backend'' zu erben, und den Konstruktur zu überschreiben. Vielleicht ist es auch nicht nötig, ich habe es nicht probiert. Ob der ''load_callback'' Parameter übergeben bekommt, weiss ich nicht, aber ich benötige keinen Parameter.&lt;br /&gt;
&lt;br /&gt;
Der ''save_callback'' erhält den Wert des Feldes, das gespeichert werden soll ($var), und den DataContainer ($dc), der zu dem Formular gehört. Meist (wie auch hier) ist es DC_Table, der DataContainer für Datenbanktabellen.&lt;br /&gt;
&lt;br /&gt;
Mein ''password''-Feld in der Datenbank wird den SHA1-Hash, also einen langen String unverständlicher hexadezimaler Zahlen enthalten. Es nützt nichts, wenn ich den im Backend im Passwort-Feld anzeige. Dort will der Admin Klartext-Passwörter eingeben. Im Load-Callback setze ich den Wert des ''password''-Felds also auf einen leeren String, egal was in der Datenbank steht:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  public function password_load_callback() &lt;br /&gt;
  { &lt;br /&gt;
    // Passwort-Feld immer leer anzeigen (Damit der User SHA1-Hash nicht sieht) &lt;br /&gt;
    return ''; &lt;br /&gt;
  } &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit wird der User schon mal nicht vom &amp;quot;Müll&amp;quot; aus der Datenbank belästigt. Umgekehrt müssen wir aber nicht das Klartext-Passwort, sondern den Hash in die Datenbank schreiben. Das macht der ''save_callback'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  public function password_save_callback($var, $dc) &lt;br /&gt;
  { &lt;br /&gt;
    // Kein neues PW angegeben: Feld nicht ändern &lt;br /&gt;
    if(strlen($var) &amp;lt; 1) return ''; &lt;br /&gt;
    // Aktuellen Datensatz aus DB holen &lt;br /&gt;
    $row = $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;SELECT * FROM tl_gw_turnierpaare WHERE id=?&amp;quot;) &lt;br /&gt;
                              -&amp;gt;execute($dc-&amp;gt;id); &lt;br /&gt;
    // PW in Passwort und Salt aufspalten &lt;br /&gt;
    list($strPassword, $strSalt) = explode(':', $row-&amp;gt;password); &lt;br /&gt;
    // Falls kein Salt vorhanden, dann erzeugen &lt;br /&gt;
        if (!strlen($strSalt)) &lt;br /&gt;
        { &lt;br /&gt;
            $strSalt = substr(md5(uniqid('', true)), 0, 23); &lt;br /&gt;
        } &lt;br /&gt;
    // SHA1-Hash aus Salt+neuem Passwort berechnen, Salt anhängen &lt;br /&gt;
    $pwd = sha1($strSalt . $var) . ':' . $strSalt; &lt;br /&gt;
    // Das resetpassword-Feld löschen &lt;br /&gt;
    $this-&amp;gt;Database-&amp;gt;prepare(&amp;quot;UPDATE tl_gw_turnierpaare SET resetpassword='' WHERE id=?&amp;quot;) &lt;br /&gt;
                              -&amp;gt;executeUncached($dc-&amp;gt;id); &lt;br /&gt;
    return $pwd; &lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls kein Passwort angegeben wurde, macht der ''save_callback'' garnichts, und gibt einen leeren String zurück. &lt;br /&gt;
&lt;br /&gt;
Das Feld ''Id'' des DataContainers enthält die ''id'' des aktuellen Datensatzes in der Datenbank. Um den Hash berechnen zu können, benötige ich das &amp;quot;alte&amp;quot; Passwort in der Datenbank. Darum hole ich mir erstmal den gesamten Datensatz mit der ID ab.&lt;br /&gt;
&lt;br /&gt;
Die Hash-Erzeugung habe ich mir beim File ''/system/libraries/User.php'' abgeschaut und funktioniert genauso wie in der Userverwaltung von TYPOlight: Der Hash wird zusammen mit einem &amp;quot;Salt&amp;quot; erzeugt, der zusammen mit dem Hash (durch Doppelpunkt getrennt) im ''password''-Feld abgespeichert wird. Existiert noch kein Salt, wird er erzeugt. Existiert der Salt schon, wird er weiterverwendet (und dafür muss ich das alte Passwort aus der Datenbank auslesen - um an den evtl. schon vorhandenen Salt zu kommen). Die Hash-Erzeugung läuft dann ziemlich straight-forward ab.&lt;br /&gt;
&lt;br /&gt;
Und fast ganz am Ende nochmal der Knackpunkt: Hier setze ich das ''resetpassword''-Feld in der Datenbank auf ''. &lt;br /&gt;
&lt;br /&gt;
Das (und leider nur das) sorgt in allen Fällen dafür, dass beim Öffnen von Datensätzen die Subpalette für das ''password''-Feld geschlossen ist.&lt;br /&gt;
&lt;br /&gt;
Abschließend gebe ich den berechneten Hash zurück. Er wird dann in die Datenbank eingetragen.&lt;br /&gt;
&lt;br /&gt;
Wichtiger Hinweis noch: ''load_callback'' und ''save_callback'' müssen doppelt geschachtelte Arrays sein, weil es mehrere Callbacks geben kann, die nacheinander aufgerufen werden, der Feldwert wird jeweils durch alle durchgeschleust. Falls man aber z.B. einen ''onSubmitCallback'' für das ganze Formular vorgeben möchte, ist das nur ein einfaches Array mit Klassennamen und Methodenname, weil es hier nur einen Callback gibt. Das ist so leider in der Referenz der möglichen Callbacks nicht dokumentiert, und hat mir kurz graue Haare beschert.&lt;br /&gt;
&lt;br /&gt;
Damit ist das Backend-Modul für die Turnierpaar-Tabelle erstmal fertig.&lt;br /&gt;
&lt;br /&gt;
Weiter wird es dann (endlich) mit dem Frontendmodul für die Turnierpaarliste gehen.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-05_Backend_Language_Files</id>
		<title>TEE-05 Backend Language Files</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-05_Backend_Language_Files"/>
				<updated>2010-07-07T10:27:44Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Langu…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Language Files=&lt;br /&gt;
Nun geht es an die Sprachfiles, um das Backend-Modul &amp;quot;hübsch&amp;quot; zu machen.&lt;br /&gt;
&lt;br /&gt;
Ich demonstriere es für die deutschen Sprachfiles im ''/system/modules/gw_turnierpaare/languages/de/''-Verzeichnis. Englisch geht genau analog :-).&lt;br /&gt;
&lt;br /&gt;
Zunächst definieren wir die Namen der Back- und Frontendmodule, und einen kurzen Erklärungstext dazu. Das wird in ''modules.php'' gemacht:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Back end modules &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['MOD']['gw_turnierpaare'] = array('Turnierpaare', 'Verwaltung der Turnierpaare und der Meldeliste.'); &lt;br /&gt;
/** &lt;br /&gt;
 * Front end modules &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['FMD']['gw_turnierpaarliste'] = array('Turnierpaarliste', 'Dieses Modul zeigt die Turnierpaarliste an'); &lt;br /&gt;
$GLOBALS['TL_LANG']['FMD']['gw_meldeliste'] = array('Meldeliste', 'Dieses Modul zeigt die Meldeliste an');&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Bezeichner hinter 'MOD' und 'FMD' müssen die sein, dir wir im config/config.php der Extension definiert haben. Die entsprechenden Texte für die beiden geplanten Frontendmodule habe ich hier auch schon mal eingetragen, auch wenn es die Module noch nicht gibt...&lt;br /&gt;
&lt;br /&gt;
Die Texte für die Backendfelder sind in tl_gw_turnierpaare.php definiert, entsprechend dem Namen der Datenbanktabelle. Die in der DCA-Record-Definition deklarierten Felder müssen wir mit Text füllen. Das ist ziemlich straight-forward:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Fields &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname']    = array('Nachname des Partners', 'Bitte den Nachnamen des (m&amp;amp;auml;nnlichen) Partners eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnervorname']     = array('Vorname des Partners', 'Bitte den Vornamen des (m&amp;amp;auml;nnlichen) Partners eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinnachname']  = array('Nachname der Partnerin', 'Bitte den Nachnamen des (weiblichen) Partners eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinvorname']   = array('Vorname der Partnerin', 'Bitte den Vornamen des (weiblichen) Partners eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startgruppe']        = array('Startgruppe', 'Bitte die Startgruppe (JUG, HGR, SEN, ...) des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklasselatein']  = array('Startklasse Latein', 'Bitte die Startklasse (Latein) des Paares eingeben. Kein Lateinstartbuch = &amp;quot;-&amp;quot;'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklassestandard'] = array('Startklasse Standard', 'Bitte die Startklasse (Standard) des Paares eingeben. Kein Standardstartbuch = &amp;quot;-&amp;quot;'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktiv']              = array('Aktiv', 'Bitte angeben, ob das Paar noch aktiv ist'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivseit']          = array('Aktiv seit', 'Bitte Jahreszahl des ersten Starts angeben (z.B. 2005)'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivbis']           = array('Aktiv bis', 'Bitte Jahreszahl des letzten Starts angeben, wenn das Paar nicht mehr aktiv is&lt;br /&gt;
t (z.B. 2008)'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['password']           = array('Passwort', 'Bitte ein Passwort f&amp;amp;uuml;r das Paar anlegen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeanschrift']     = array('Anschrift anzeigen', 'Anschrift in der Visitenkarte sichtbar?'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['anschrift']          = array('Anschrift', 'Bitte Anschrift des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigetelefon']       = array('Telefonnummer anzeigen', 'Telefonnummer in der Visitenkarte sichtbar?'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['telefon']            = array('Telefonnummer', 'Bitte Telefonnummer des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigefax']           = array('Faxnummer anzeigen', 'Faxnummer in der Visitenkarte sichtbar?'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['fax']                = array('Faxnummer', 'Bitte Faxnummer des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigemobil']         = array('Mobilnummer anzeigen', 'Mobilnummer in der Visitenkarte sichtbar?'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['mobil']              = array('Mobilnummer', 'Bitte Mobilnummer des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeemail']         = array('Email-Adresse anzeigen', 'Email-Adresse in der Visitenkarte sichtbar?'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['email']              = array('Email-Adresse', 'Bitte Emailadresse des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigehomepage']      = array('Homepage-Adresse anzeigen', 'Homepage-Adresse in der Visitenkarte sichtbar?'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['homepage']           = array('Homepage-Adresse', 'Bitte Homepage-Adresse des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['beschreibung']       = array('Beschreibungstext', 'Bitte Beschreibungstext des Paares eingeben'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['bild']               = array('Paarbild', 'Bitte ein Paarbild ausw&amp;amp;auml;hlen'); &lt;br /&gt;
/** &lt;br /&gt;
 * Reference &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['name_legend']          = 'Namen'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['classes_legend']       = 'Startdaten'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktiv_legend']         = 'Aktiv'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['password_legend']      = 'Passwort'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['contact_legend']       = 'Kontakt'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['beschreibung_legend']  = 'Beschreibung'; &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['bild_legend']          = 'Bild'; &lt;br /&gt;
/** &lt;br /&gt;
 * Buttons &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['new']    = array('Neues Paar', 'Ein neues Turnierpaar anlegen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['edit']   = array('Editieren', 'Das Turnierpaar editieren'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['copy']   = array('Paar kopieren', 'Das Turnierpaar in die Zwischenablage kopieren'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['delete'] = array('Paar löschen', 'Das Turnierpaar aus der Liste entfernen'); &lt;br /&gt;
$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['show']   = array('Details', 'Die Detailansicht des Turnierpaars anzeigen');&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unterschieden werden die Texte für die Eingabefelder, die aus Überschrift/Bezeichner für das Feld und dem darunter angezeigten Beschreibungstext bestehen, den Texten für Palettenüberschriften (mittlerer Teil) und den Texten für die Buttons in den Masken (letzter Teil). Umlaute müssen HTML-üblich durch ihre Ersatzcodes (ä = &amp;amp;auml; usw.) dargestellt werden. Die Beschreibungstexte sollten auch nicht zu lang werden.&lt;br /&gt;
&lt;br /&gt;
Ich habe in der DCA-Definition auch Referenzen auf Sprach-Strings für die Eigenschaft ''explanation'' angegeben, z.B. so:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname_explanation'],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
allerdings habe ich nicht erkennen können, wo das benutzt wird. Vielleicht nur in bestimmten Situatuionen/Konfigurationen. Ich habe all diese Referenzen bei jedem Feld aus meiner DCA-Konfiguration also wieder entfernt.&lt;br /&gt;
&lt;br /&gt;
Die Backend-Maske sieht jetzt so aus:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_015.png]]&lt;br /&gt;
&lt;br /&gt;
==Diskussion==&lt;br /&gt;
'''user: deerwood'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Zitat:&lt;br /&gt;
Umlaute müssen HTML-üblich durch ihre Ersatzcodes (ä = &amp;amp;auml; usw.) dargestellt werden &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Nein. UTF8 Zeichen/Editoren sind heutzutage angesagt   . Z.B. Notepad++ oder Eclipse oder ... oder ...&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
vielen Dank für den Hinweis. Ich nutze PSPad, den ich eigentlich als &amp;quot;vernünftigen&amp;quot; Editor ansehe, aber trotzdem stand der Zeichensatz auf &amp;quot;ANSI&amp;quot;. Mit UTF8 geht es natürlich auch mit Umlauten ;-). Da muss ich in Zukunft mehr drauf achten.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-04_Backend_DCA</id>
		<title>TEE-04 Backend DCA</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-04_Backend_DCA"/>
				<updated>2010-07-07T10:23:53Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Wir w…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Wir wagen uns in das DCA-Land=&lt;br /&gt;
Jetzt kommt es zu einem (vermutlich) harten Brocken. Mein backend-Modul wird links in der Navigation des Backends (in der Sidebar) angezeigt, aber man kann noch keine Datensätze anlegen oder verändern. Dafür müssen wir einen passenden ''DCA-Record'' anlegen. Ich werde mich wieder vom [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorial] und der Referenz zu den [http://www.typolight.org/dca.html DCA-Records] leiten lassen. Die Referenz ist schon mal erschlagend-beeindruckend.&lt;br /&gt;
&lt;br /&gt;
Mithilfe der DCA-Records erstellt TYPOlight die Masken, mit denen man im Backend die Tabellen füllen, verändern und löschen kann. In ''/system/modules/gw_turnierpaare/dca/tl_gw_turnierpaare.php'' hat der ''Extension-Generator'' freundlicherweise schon ein Skelett für einen DCA-Record für die Tabelle ''tl_gw_turnierpaare'' angelegt.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$GLOBALS['TL_DCA']['tl_gw_turnierpaare'] = array &lt;br /&gt;
( &lt;br /&gt;
    // Config &lt;br /&gt;
    'config' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'dataContainer'               =&amp;gt; 'Table', &lt;br /&gt;
        'enableVersioning'            =&amp;gt; true &lt;br /&gt;
    ), &lt;br /&gt;
...  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der zweite Array-Key in $GLOBALS ist der Name unserer Tabelle. Im darauffolgenden mehrfach verschachtelten Array gibt es zunächst die ''config''-Sektion. Hier wird zunächst festgehalten, dass es sich bei der Datenquelle um eine Tabelle handelt. Laut Referenz sind auch noch File und Folder vorgesehen. Sicherlich sind Tabellen der am häufigsten gebrauchte Datacontainer. ''enableVersioning'' erlaubt die Versionierung der Einträge - das ist OK und passt mir ins Konzept. Die Referenz verrät mir, daß ich eine &amp;quot;child Table&amp;quot; angeben kann. Da die Turniermeldungen Childs der Turnierpaare werden soll, ergänze ich also&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'ctable'                      =&amp;gt; 'tl_gw_meldungen'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die verbleibenden Optionen in ''config'' erscheinen mir nicht weiter von Bedeutung. Weiter geht es mit dem Abschnitt ''list'', und dort mit ''sorting'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // List &lt;br /&gt;
    'list' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'sorting' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'mode'                    =&amp;gt; 1, &lt;br /&gt;
            'fields'                  =&amp;gt; array(''), &lt;br /&gt;
            'flag'                    =&amp;gt; 1 &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sortierart und Sortierreihenfolge sind für mich erstmal ok, da ich gerne nach Nachnamen von Herrn und Dame sortieren würde, verändere ich die Zeile mit ''fields'' auf:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname','partnerinnachname'),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als nächstes kommt ein Block ''label'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'label' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'fields'                  =&amp;gt; array(''), &lt;br /&gt;
            'format'                  =&amp;gt; '%s' &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier scheint es wohl darum zu gehen, was in der Liste der schon bestehenden Tabelleneinträge eingezeigt wird. Ich verändere die Zeilen auf&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname','partnervorname','partnerinnachname','partnerinvorname','startgruppe','startklassestd','startklasselat'), &lt;br /&gt;
            'format'                  =&amp;gt; '%s, %s und %s, %s - %s %s LAT / %s STD'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Etwas &amp;quot;domain-specific knowledge&amp;quot;: Startgruppe ist im Prinzip die Altersklasse, Startklasse ist die Leistungsklasse (Die &amp;quot;Liga&amp;quot;), in der das Paar tanzt, und zwar unterschieden nach lateinamerikanischen und Standardtänzen. Diese Infos sind für den Sportwart interessant und sollten in der Übersichtsliste vorhanden sein. Die &amp;quot;''%s''&amp;quot; im format-String werden in der Reihenfolge mit Feldinhalten befüllt, wie wir sie obendrüber im Array angegeben haben. Der Aufbau des format-Strings sollte PHP- (oder C-)Programmierern bekannt sein. Dann kommt ein Abschnitt ''global_operations'' und ''operations'', den ich aber gar nicht verändern will:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'global_operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'all' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['MSC']['all'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=select', &lt;br /&gt;
                'class'               =&amp;gt; 'header_edit_all', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ) &lt;br /&gt;
        ), &lt;br /&gt;
        'operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'edit' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['edit'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=edit', &lt;br /&gt;
                'icon'                =&amp;gt; 'edit.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'copy' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['copy'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=copy', &lt;br /&gt;
                'icon'                =&amp;gt; 'copy.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'delete' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['delete'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=delete', &lt;br /&gt;
                'icon'                =&amp;gt; 'delete.gif', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;if (!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\')) return false;Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ), &lt;br /&gt;
            'show' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['show'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=show', &lt;br /&gt;
                'icon'                =&amp;gt; 'show.gif' &lt;br /&gt;
            ) &lt;br /&gt;
        ) &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Laut Referenz sollte ''global_operations'' ein Unterpunkt von ''operations'' sein, im Skelett-File des Extension-Generators stehen sie aber auf gleicher Ebene. Bin etwas verwundert, aber wird schon funktionieren. Nächster Abschnitt im vorgegeben File sind ''palettes'' und ''subpalettes''. Leider stehen die nicht in der Referenz, und auch die Seite über ''palettes'' macht mich nicht so richtig schlauer.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '' &lt;br /&gt;
    ), &lt;br /&gt;
    // Subpalettes &lt;br /&gt;
    'subpalettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        ''                            =&amp;gt; '' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Blick ins [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorial] verrät, dass man unter ''default'' die Felder angeben kann, die in Paletten sortiert werden sollen: Felder innerhalb der Palette mit Komma getrennt, Beginn einer neuen Palette durch ein Semikolon.&lt;br /&gt;
Da ich es zeitlich für diesen Post nicht schaffen werde, alle Felder meiner ''tl_gw_turnierpaare''-Tabelle zu definieren, will ich zunächst nur die Namensfelder definieren, und zum Testen 2 Paletten benutzen. Ich editiere den ''palettes''-Eintrag also in&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; 'partnernachname,partnervorname;partnerinnachname,partnerinvorname' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Subpalettes'' lässt mich weiterhin ratlos, also Finger weg davon. Der letzte Teil der Skelett-Datei (und hier wird es richtig spannend!) ist das ''fields''-Array:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare'][''], &lt;br /&gt;
            'exclude'                 =&amp;gt; true, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'maxlength'=&amp;gt;255&lt;br /&gt;
) &lt;br /&gt;
        ) &lt;br /&gt;
    ) &lt;br /&gt;
);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich halte mich erstmal an das Skelett, und füge nur die Feldnamen hinzu, und vervielfältige den Block auf insgesamt 4 Stück:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'partnernachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'maxlength'=&amp;gt;64) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnervorname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnervorname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnerinnachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinnachname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnerinvorname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinvorname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ) &lt;br /&gt;
    )  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Labels müssen wir später noch in den Sprachfiles definieren, ''exclude'' = ''true'' bedeutet, dass nur Admins das Feld sehen können. Da später ein Nicht-Admin die Tebelle pflegen können soll, setze ich es also überall auf ''false''. Ich hoffe mein Gedankengang ist da richtig. Wir setzen für jedes Feld die Maximallänge auf 64 Zeichen, und nur der Partner-Nachname ist verpflichtend. Warum nicht auch Vorname und der Namen der Partnerin? Ich brauche für meine Anwendung EINE klitzekleine Ausnahme, in der ich gerne eine Mannschaft in die Startliste eintragen würde. Deren Name würde dann in ''partnernachname'' stehen, die restlichen Felder wären leer.&lt;br /&gt;
&lt;br /&gt;
Für den nächsten Post wird das alles noch verfeinert, weitere Optionen für die Felder hinzugefügt und vor allem alle Felder der Tabelle im DCA-Record definiert. Aber erstmal ein kleines, bescheidenes Zwischenergebnis zur Motivation:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_004.png]]&lt;br /&gt;
&lt;br /&gt;
Und man kann auch schon was eingeben:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_005.png]]&lt;br /&gt;
&lt;br /&gt;
Da Startgruppe und Klasse(n) noch nicht einzugeben sind, bleiben die in der Übersichtsliste noch leer. Aber: Grundlegend funktioniert das schonmal, und auch den Begriff ''palette'' habe ich jetzt (anhand des Screenshots) verstanden.&lt;br /&gt;
&lt;br /&gt;
Im nächsten Post wird das alles erweitert und &amp;quot;poliert&amp;quot;. Zur Übersicht nochmal mein aktueller Stand der Datei ''/system/modules/gw_turnierpaare/dca/tl_gw_turnierpaare.php'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Table tl_gw_turnierpaare  &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_DCA']['tl_gw_turnierpaare'] = array &lt;br /&gt;
( &lt;br /&gt;
    // Config &lt;br /&gt;
    'config' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'dataContainer'               =&amp;gt; 'Table', &lt;br /&gt;
        'enableVersioning'            =&amp;gt; true, &lt;br /&gt;
        'ctable'                      =&amp;gt; 'tl_gw_meldungen' &lt;br /&gt;
    ), &lt;br /&gt;
    // List &lt;br /&gt;
    'list' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'sorting' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'mode'                    =&amp;gt; 1, &lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname','partnerinnachname'), &lt;br /&gt;
            'flag'                    =&amp;gt; 1 &lt;br /&gt;
        ), &lt;br /&gt;
        'label' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname','partnervorname','partnerinnachname','partnerinvorname','startgruppe','startklassestd','startklasselat'), &lt;br /&gt;
            'format'                  =&amp;gt; '%s, %s und %s, %s - %s %s LAT / %s STD' &lt;br /&gt;
        ), &lt;br /&gt;
        'global_operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'all' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['MSC']['all'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=select', &lt;br /&gt;
                'class'               =&amp;gt; 'header_edit_all', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ) &lt;br /&gt;
        ), &lt;br /&gt;
        'operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'edit' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['edit'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=edit', &lt;br /&gt;
                'icon'                =&amp;gt; 'edit.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'copy' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['copy'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=copy', &lt;br /&gt;
                'icon'                =&amp;gt; 'copy.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'delete' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['delete'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=delete', &lt;br /&gt;
                'icon'                =&amp;gt; 'delete.gif', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;if (!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\')) return false; Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ), &lt;br /&gt;
            'show' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['show'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=show', &lt;br /&gt;
                'icon'                =&amp;gt; 'show.gif' &lt;br /&gt;
            ) &lt;br /&gt;
        ) &lt;br /&gt;
    ), &lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; 'partnernachname,partnervorname;partnerinnachname,partnerinvorname' &lt;br /&gt;
    ), &lt;br /&gt;
    // Subpalettes &lt;br /&gt;
    'subpalettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        ''                            =&amp;gt; '' &lt;br /&gt;
    ), &lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'partnernachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'maxlength'=&amp;gt;64) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnervorname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnervorname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnerinnachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinnachname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnerinvorname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinvorname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ) &lt;br /&gt;
    ) &lt;br /&gt;
);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Verwirrung im DCA-Land==&lt;br /&gt;
Nachdem ich einige Testpaare in meine &amp;quot;Minimalmaske&amp;quot; eingetragen habe, stelle ich fest, dass es nicht ganz so aussieht, wie ich es gerne hätte.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_006.png]]&lt;br /&gt;
&lt;br /&gt;
Für jeden Herrennachnamen gibt es eine eigene Gruppenüberschrift. Das ist irgendwie suboptimal, und verschwendet Platz. Ich hätte gerne keine Gruppenüberschriften, oder nur &amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;, &amp;quot;C&amp;quot;, usw...Ich vermute, dass das mit dem Eintrag ''['list']['sorting']['flag']'' zusammenhängt, den ich auf &amp;quot;1&amp;quot; hatte, laut Referenz ''Sort by initial letter ascending'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // List &lt;br /&gt;
    'list' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'sorting' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'mode'                    =&amp;gt; 1, &lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname', 'partnervorname', 'partnerinnachname', 'partnerinvorname'), &lt;br /&gt;
            'flag'                    =&amp;gt; 1 &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich spiele also etwas mit ''flag'' herum, und stelle fest: Irgendwie beeinflusst das garnix. &lt;br /&gt;
*  2 = ''Sort by initial letter descending'', &lt;br /&gt;
*  3 = ''Sort by initial two letters ascending'', &lt;br /&gt;
*  4 = ''Sort by initial two letters descending'', &lt;br /&gt;
* 11 = ''Sort ascending'' oder &lt;br /&gt;
* 12 = ''Sort descending'' &lt;br /&gt;
machen in meiner Auflistung nirgendwo irgendeinen Unterschied. Immer wird stur ''ascending'' in der Reihenfolge meiner Sortierfelder sortiert, und für jeden &amp;quot;Unique&amp;quot; Herrennachnamen gibt es eine Gruppenüberschrift.&lt;br /&gt;
 &lt;br /&gt;
In meiner Verzweifelung setze ich ''['list']['sorting']['mode']'' auf 0, laut Referenz ''Records are not sorted''. Das Ergebnis sieht so aus&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_007.png]]&lt;br /&gt;
&lt;br /&gt;
Immerhin die Gruppenüberschriften weg...und stur ''ascending'' nach meinen Sortierfeldern sortiert. Fast schon unnötig zu erwähnen, dass ''flag'' auch hier keine Wirkung zu haben scheint.&lt;br /&gt;
&lt;br /&gt;
Um das Sortieren vielleicht &amp;quot;von Hand&amp;quot; steuern zu können, füge ich streng nach Referenz die Zeile&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'panelLayout'             =&amp;gt; 'search,sort,filter'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
hinzu in der Erwartung, dass mir dann in der Übersicht die entsprechenden Optionen angeboten werden. Leider - nichts. Die Übersichtsliste der Turnierpaare verändert sich überhaupt nicht.&lt;br /&gt;
&lt;br /&gt;
Meine ''['list']['sorting']''-Sektion sieht nun so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'sorting' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'mode'                    =&amp;gt; 0, &lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname', 'partnervorname', 'partnerinnachname', 'partnerinvorname'), &lt;br /&gt;
            'flag'                    =&amp;gt; 1, &lt;br /&gt;
            'panelLayout'             =&amp;gt; 'search,sort,filter' &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jemand eine Ahnung, warum das Verhalten so ist, bzw. warum mich die Referenz für die DCA-Records so im Stich lässt?&lt;br /&gt;
Danke...&lt;br /&gt;
&lt;br /&gt;
==Leichte Entwirrung im DCA-Land==&lt;br /&gt;
Lösung gefunden! Bei den einzelnen ''field''-Beschreibungen muss noch die Freigabe zum Sortieren, Filtern und Suchen gegeben werden. Das sieht jetzt so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'partnernachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'filter'                  =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 1, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'maxlength'=&amp;gt;64) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnervorname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnervorname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnerinnachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinnachname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'filter'                  =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 1, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnerinvorname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinvorname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ) &lt;br /&gt;
    )  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit Ergebnis:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_008.png]]&lt;br /&gt;
&lt;br /&gt;
Schon besser, auch wenn die Dropdown-Liste hinter ''Suchen:'' noch leer ist. Vielleicht liegt das an den noch fehlenden Feld-Labels in den Sprachdateien. Nur warum man ''flag'' bei den einzelnen Fields und nochmal global angeben muss, das will ich noch nicht verstehen...&lt;br /&gt;
&lt;br /&gt;
Ergänzung: Und wenn ich ''['sorting']['mode']'' auf 2 setze, dann kann ich sogar mein Sortierfeld auswählen....sehr schön...&lt;br /&gt;
&lt;br /&gt;
==DCA-Polishing==&lt;br /&gt;
Nachdem also die leichten Verwirrungen rund um den DCA-Record beseitigt sind, geht es weiter damit, die Backend-&amp;quot;Maske&amp;quot; für die ''tl_gw_turnierpaare''-Tabelle zu definieren und zu &amp;quot;polieren&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Zu jedem Feld lege ich einen Verweis auf den Erklärungs-Text an, der unter dem Eingabefeld angezeigt wird, z.B. für das ''partnernachname''-Feld im Abschnitt ''['fields']['partnernachname']'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname_explanation'],  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der entsprechende Text muss in den Sprachfiles natürlich noch eingetragen werden - später.&lt;br /&gt;
&lt;br /&gt;
Außerdem ergänze ich den ''eval''-Wert meiner bisherigen 4 Eingabefelder um den Wert'' 'minlength' =&amp;gt; 1'', um bei den namen eine Mindestlänge zu erzwingen (Beim Wert 1 wahrscheinlich überflüssig, aber egal).&lt;br /&gt;
&lt;br /&gt;
Bei dem Nachnamen des Partners und der Partnerin ergänze ich außerdem '''tl_class' =&amp;gt; 'w50'''. Das sorgt dafür, dass zwei Felder nebeneinander dargestellt werden. Das Feld mit der w50-Klasse links, das darauffolgende rechts. Dadurch werden Nachname und Vorname jeder Person nebeneinander in einer Zeile dargestellt.&lt;br /&gt;
&lt;br /&gt;
Meine Einstellungen für das ''partnernachname''-Feld sehen jetzt so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'partnernachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname_explanation'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'filter'                  =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 1, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;64, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wo ich gerade noch optisch etwas aufräume, baue ich den Eintrag ''default'' unter ''palettes'' so um:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname;' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''{name_legend}'' legt die Überschrift für die &amp;quot;Palette&amp;quot; fest (also die Felder bis zum nächsten Semikolon). Der Wert muss später im Sprachenfile definiert werden. Ich habe nun alle 4 Textfelder in einer Palette. Optisches Ergebnis:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_009.png]]&lt;br /&gt;
&lt;br /&gt;
Wenn man sich &amp;quot;vernünftige&amp;quot; Überschriften aus dem Sprachfile dazu vorstellt, schon mal ganz OK :-).&lt;br /&gt;
&lt;br /&gt;
Nun geht es um die noch fehlenden Tabellenfelder.&lt;br /&gt;
&lt;br /&gt;
Zunächst kommt ''startgruppe'', das bezeichnet die Altersklasse des Paars. Das Feld soll ''mandatory'' sein, aber auch eine &amp;quot;leere Option&amp;quot; erlauben. Ich will als Ausnahme auch eine Mannschaft in die Paarliste eingeben können, und Mannschaften haben keine Altersklasse. Mein Code für das ''field'' sieht so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'startgruppe' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startgruppe'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startgruppe_explanation'],&lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'options'                 =&amp;gt; array('KIN I','KIN II', 'JUN I', 'JUN II', 'JUG', 'HGR', 'HGR II', 'SEN I', 'SEN II', 'SEN III', 'SEN IV'), &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'includeBlankOption' =&amp;gt; true) &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich wähle also ein ''select'', also eine Drop-Down-Box. In ''options'' liste ich die möglichen Altersgruppen auf, im ''eval''-Bereich gebe ich noch an, dass eine leere Option hinzugefügt werden soll.&lt;br /&gt;
&lt;br /&gt;
Dann kommen ''startklasselatein'' und ''startklassestandard''. Inhaltlich kann in beiden Feldern dasselbe drinstehen, darum ist es fast nur Copy&amp;amp;Paste für das zweite Feld. Die Definition sieht so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'startklasselatein' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklasselatein'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklasselatein_explanation'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'options'                 =&amp;gt; array('E','D', 'C', 'B', 'A', 'S', 'PRO', 'LL', 'OL', 'RL', '2. BL', '1. BL'), &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'includeBlankOption' =&amp;gt; true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier wieder eine Drop-Down-Box mit Optionen und Möglichkeit der &amp;quot;leeren Option&amp;quot;. Durch ''tl_class =&amp;gt; w50'' wird die Drop-Down-Box nach links gerückt, so dass rechts daneben noch die gleichartige Box für ''startklassestandard'' passt. Die hat natürlich KEIN ''tl_class =&amp;gt; w50''!&lt;br /&gt;
&lt;br /&gt;
Eigentlich müsste ich prüfen, dass entweder in ''startklasselatein'' oder ''startklassestandard'' ein Wert ausgewählt ist (also nicht in beiden Feldern die leere Option gewählt wurde), aber das bürde ich zunächst mal dem User auf, vielleicht ergänze ich hier später eine Validation durch einen Hook.&lt;br /&gt;
&lt;br /&gt;
Zur Motivation will ich meine drei neuen Felder auch in im backend sehen, dazu muss ich sie zur Liste der Paletten hinzufügen. Ich packe sie in eine eigene Palette mit Überschrift.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname;&lt;br /&gt;
{classes_legend},startgruppe,startklasselatein,startklassestandard' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ergebnis:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_010.png]]&lt;br /&gt;
&lt;br /&gt;
Weiter geht's, jetzt folgen die Felder ''aktiv'', ''aktivseit'' und ''aktivbis''.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'aktiv' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktiv'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktiv_explanation'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'isBoolean' =&amp;gt; true) &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Aktiv'' wird eine Checkbox. Ich weiß zwar nicht, was es für eine Bedeutung hat, aber da eine CheckBox immer &amp;quot;Boolean&amp;quot; ist, setze ich in ''eval'' ''isBoolean =&amp;gt; true''.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'aktivseit' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivseit'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivseit_explanation'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 4, 'maxlength' =&amp;gt; 4, 'rgxp' =&amp;gt; 'digit', 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'aktivbis' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivbis'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivbis_explanation'],&lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 4, 'maxlength' =&amp;gt; 4, 'rgxp' =&amp;gt; 'digit') &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''aktivseit'' und ''aktivbis'' sollen nur eine Jahreszahl enthalten. Darum setze ich Minimal- und Maximallänge auf 4 und lasse durch ''rgxp'' nur Zahlen zu. Man hätte auch eine Dropdown-Box mit Jahreszahlen drin nehmen können. Ich denke beides hat Vor- und Nachteile. Sich durch DropDown-Boxen zu scrollen, die bei &amp;quot;1900&amp;quot; anfangen, wenn man nach &amp;quot;2004&amp;quot; will, ist auch kein Vergnügen. Das erste Feld setze ich mit ''tl_class =&amp;gt; w50'' nach links, um das zweite Feld daneben darstellen zu können.&lt;br /&gt;
&lt;br /&gt;
Ich ergänze die Paletten-Definition um&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{aktiv_legend:hide},aktiv,aktivseit,aktivbis;  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da die Felder nicht so oft editiert werden, schließe ich die Palette defaultmäßig.&lt;br /&gt;
&lt;br /&gt;
Nun kommt schon ein kleiner Sonderfall: ''password''. Dies soll das Paar-Passwort sein, was zum Eintragen von Turnierergebnissen oder geänderten persönlichen Daten im Frontend dient. Ich will das nur in eigenen PHP-Skripten nutzen, von daher habe ich hier alle Freiheiten, wie ich das realisiere.&lt;br /&gt;
&lt;br /&gt;
Ich möchte gerne, dass der Sportwart in diesem Feld ein Klartextpasswort eingeben kann. In die Datenbank soll aber nur der MD5-Hash des Passworts gelangen. Momentan plane ich, dass in dem Textfeld einfach der MD5-Hash angezeigt wird, wenn man aber etwas in dieses Feld eingibt, dass es dann aber durch einen Hook in den Hash umgewandelt wird, bevor es in der Datenbank gespeichert wird. Um die Realisation kümmere ich mich später. Erstmal soll es ein ganz normales Text-Feld sein:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'password' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['password'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['password_explanation'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength' =&amp;gt; 64) &lt;br /&gt;
        )  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieses Feld soll (alleine) in einer eigenen Palette stehen, darum ergänze ich die Palettendefinition um:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{password_legend:hide},password;  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zwischenstand der Backend-Maske:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_011.png]]&lt;br /&gt;
&lt;br /&gt;
Und nochmal die gesamte Paletten-Definition:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname;&lt;br /&gt;
{classes_legend},startgruppe,startklasselatein,startklassestandard;{aktiv_legend:hide},aktiv,aktivseit,aktivbis;{password_legend:hide},password;' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Leider ist damit schon wieder das Ende meiner zur Verfügung stehenden Zeit erreicht (Sorry, wenn es zu langsam voran geht). Bald geht es weiter.&lt;br /&gt;
&lt;br /&gt;
== Ein Bug, ein Bug!==&lt;br /&gt;
Nachdem man jetzt Startklassen eingeben, entdecke ich natürlich gleich einen Bug, und zwar in ''['list']['label']['fields']''.&lt;br /&gt;
&lt;br /&gt;
VORHER (falsch):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname','partnervorname','partnerinnachname','partnerinvorname','startgruppe','startklassestd','startklasselat'),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
NACHHER (richtig):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname','partnervorname','partnerinnachname','partnerinvorname','startgruppe','startklassestandard','startklasselatein'),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
D.h. die beiden Felder für die Startklasse Standard und Latein waren falsch benannt. Sorry.&lt;br /&gt;
&lt;br /&gt;
Und weiter geht es mit Bugs:&lt;br /&gt;
Wenn ich bei Feldern, die eine &amp;quot;leere Option&amp;quot; zulassen, trotzdem in '''eval' mandatory =&amp;gt; true'' fordere, kann die leere Option nicht ausgewählt werden. Gut, irgendwie auch logisch. Aus diesem Grund setze ich bei ''startgruppe'', ''startklasselatein'' und ''startklassestandard'' &amp;quot;'''mandatory' =&amp;gt; false''&amp;quot;, um auch die leere Option zuzulassen.&lt;br /&gt;
&lt;br /&gt;
Und letzter kleiner Fehler:&lt;br /&gt;
Im ''format''-String für die Zeilen in der Übersicht der Turnierpaare ''['list']['label']['format']'' ist LAT und STD vertauscht, ich drehe das um. Neu:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'format'                  =&amp;gt; '%s, %s und %s, %s - %s %s STD / %s LAT'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Nochmals anders==&lt;br /&gt;
Tjaja, wie das bei so einem Tagebuch im Gegensatz zum &amp;quot;durchgeplanten und polierten&amp;quot; Tutorial so ist: Ich habe mir nochmal was anders überlegt.&lt;br /&gt;
&lt;br /&gt;
Ich habe mich entschlossen, die Felder ''startklasselatein'' und ''startklassestandard'' doch ''mandatory'' zu machen, aber als Option eine Leer-Option &amp;quot;-&amp;quot; hinzuzufügen. So ist der Benutzer gezwungen, explizit anzugeben, dass ein Paar keine Startklasse in einer der beiden Sektionen hat, und in meiner Paarübersicht sieht es besser aus, wenn z.B. vor &amp;quot;LAT&amp;quot; noch ein Strich steht, statt einfach garnichts.&lt;br /&gt;
&lt;br /&gt;
Bei beiden Feldern sieht der Eintrag in ''['fields']'' jetzt also so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'options'                 =&amp;gt; array('-', 'E','D', 'C', 'B', 'A', 'S', 'PRO', 'LL', 'OL', 'RL', '2. BL', '1. BL'), &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true)  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dann habe ich noch entdeckt, dass man eine Checkbox nicht ''mandatory'' machen darf, weil dann MUSS sie nämlich angehakt werden. Ist irgendwie suboptimal. Also nochmal den Eintrag ''['fields']['aktiv']['eval']'' geändert auf:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true)  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schließlich habe ich den Format-String für die Turnierpaar-Übersicht nochmal überarbeitet. Damit die relevantesten Elemente hervorstechen gebe ich die Nachnamen der Partner fett aus, ebenso die Startgruppe. Die Startklassen zusätzlich in orange (Standard) und rot (Latein). Die Startpässe der Paare in der jeweiligen Sektion haben die gleichen Farben, so dass dies für den Eingeweihten eine natürliche Assoziation ist.&lt;br /&gt;
&lt;br /&gt;
''['list']['label']['format']'' lautet jetzt:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'format'                  =&amp;gt; '&amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt;, %s und &amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt;, %s - &amp;lt;span style=&amp;quot;font-weight: bold; margin-left: 5px&amp;quot;&amp;gt;%s &amp;lt;span style=&amp;quot;color: orange; margin-left: 5px;&amp;quot;&amp;gt;%s STD&amp;lt;/span&amp;gt; / &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;%s LAT&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und sieht so aus:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_012.png]]&lt;br /&gt;
&lt;br /&gt;
Aber im nächsten Post geht es endlich mit den restlichen Feldern der ''tl_gw_turnierpaare''-Tabelle weiter.&lt;br /&gt;
==DCA - Almost there==&lt;br /&gt;
Schritt 4 scheint kein Ende zu nehmen. Wie erwartet erweist sich das Thema &amp;quot;DCA&amp;quot; als harter Brocken.&lt;br /&gt;
&lt;br /&gt;
Zunächst geht es weiter mit den restlichen Feldern der ''tl_gw_turnierpaare''-Tabelle. Für Anschrift, Telefonnummer, Fax, Mobilnummer, Email-Adresse und Homepage gibt es jeweils ein Flag, ob es im öffentlichen Profil angezeigt werden soll. Ist es nicht gesetzt, sind die Daten nur im Backend sichtbar. So kann der Sportwart das Paar evtl. erreichen, falls notwendig&lt;br /&gt;
&lt;br /&gt;
Statt die Anschrift in Straße, PLZ, Ort, usw. aufzusplitten, habe ich hierfür eine ''textarea'' vorgesehen. Im DCA sieht das so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'anschrift' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['anschrift'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['anschrift_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'textarea', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'cols' =&amp;gt; 40, 'rows' =&amp;gt; 5) &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alles wie gehabt, zusätzlich geben ''cols'' und ''rows'' die Spalten und Zeilen des Eingabebereichs an. &lt;br /&gt;
&lt;br /&gt;
Die Definition für das Flag, ob die Anschrift öffentlich angezeigt werden soll, ist so wie beim Feld ''aktiv'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'zeigeanschrift' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeanschrift'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeanschrift_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true) &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nicht Besonderes!&lt;br /&gt;
Die Felder für Telefon, Fax, Mobilnummer, EMail und Homepage sind jeweils Textfelder, denen ich je nach Art die passende Regular Expression zur Überprüfung der Inhalte zuweise. Zusätzlich hat jedes Feld die &amp;quot;Anzeigen&amp;quot;-Checkbox:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'telefon' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['telefon'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['telefon_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength' =&amp;gt; 32, 'rgxp' =&amp;gt; 'phone') &lt;br /&gt;
        ), &lt;br /&gt;
        'zeigetelefon' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigetelefon'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigetelefon_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true, 'tl_class' =&amp;gt; 'clr m12 w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'fax' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['fax'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['fax_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength' =&amp;gt; 32, 'rgxp' =&amp;gt; 'phone') &lt;br /&gt;
        ), &lt;br /&gt;
        'zeigefax' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigefax'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigefax_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true, 'tl_class' =&amp;gt; 'clr m12 w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'mobil' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['mobil'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['mobil_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength' =&amp;gt; 32, 'rgxp' =&amp;gt; 'phone') &lt;br /&gt;
        ), &lt;br /&gt;
        'zeigemobil' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigemobil'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigemobil_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true, 'tl_class' =&amp;gt; 'clr m12 w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'email' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['email'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['email_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength' =&amp;gt; 32, 'rgxp' =&amp;gt; 'email') &lt;br /&gt;
        ), &lt;br /&gt;
        'zeigeemail' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeemail'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeemail_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true, 'tl_class' =&amp;gt; 'clr m12 w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'homepage' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['homepage'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['homepage_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength' =&amp;gt; 32, 'rgxp' =&amp;gt; 'url') &lt;br /&gt;
        ), &lt;br /&gt;
        'zeigehomepage' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigehomepage'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigehomepage_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true, 'tl_class' =&amp;gt; 'clr m12 w50') &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ''tl_class''-Werte sind so gewählt, dass jede &amp;quot;Anzeigen&amp;quot;-Checkbox links in einer Reihe mit dem entsprechenden Textfeld (rechts) in einer Zeile steht. Ich hätte es gerne andersrum gehabt, also Textfeld links, Checkbox rechts, aber trotz viel experimentieren mit den ''tl_class''-Werten ist es mir nicht gelungen, das Layout sah immer &amp;quot;zerschossen&amp;quot; aus.&lt;br /&gt;
&lt;br /&gt;
Den Wert ''['palettes']['default']'' ergänze ich noch um&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
'{contact_legend:hide},zeigeanschrift,anschrift,zeigetelefon,telefon,zeigefax,fax,zeigemobil,mobil,zeigeemail,email,zeigehomepage,homepage;'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ergebnis:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_013.png]]&lt;br /&gt;
&lt;br /&gt;
''Beschreibung'' ist eine Textarea, die in eigener Palette angezeigt werden soll. Einzige Besonderheit ist hier, dass ich HTML im Inhalt zulassen will.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'beschreibung' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['beschreibung'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['beschreibung_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'textarea', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'cols' =&amp;gt; 80, 'rows' =&amp;gt; 20, 'allowHtml' =&amp;gt; true) &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Schließlich fehlt noch das Bild. Hier wollte ich eine Bilder-Auswahl wie im Content-Element &amp;quot;Bild&amp;quot; haben. Ich habe eine Weile herumexperimentiert, insbesondere mit dem Feldtyp &amp;quot;radioTable&amp;quot; (Der aber ganz falsch ist, wie mir jetzt klar ist). Lösung brachte dann ein Blick in das [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorial], wo auch so eine Bilderauswahl drin ist. Der richtige DCA-Eintrag lautet:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'bild' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'           =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['bild'], &lt;br /&gt;
            'explanation'     =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['bild_explanation'], &lt;br /&gt;
            'inputType'       =&amp;gt; 'fileTree', &lt;br /&gt;
            'eval'            =&amp;gt; array('mandatory'=&amp;gt;false, 'files'=&amp;gt;true, 'fieldType'=&amp;gt;'radio', 'filesOnly' =&amp;gt; true, 'extensions' 		=&amp;gt; 'jpg,jpeg,png,gif', 'path' =&amp;gt; 'tl_files/GW/Bilder_Turnierpaare/') &lt;br /&gt;
        )  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typ ist also ein ''fileTree'', in dem man mittels Radiobutton EIN File auswählen kann (''fieldType =&amp;gt; radio''), in dem Dateien mit den Erweiterungen jpeg,jpg,png und gif angezeigt werden (''extensions''), in dem Unterverzeichnisse UND Dateien angezeigt werden (''files =&amp;gt; true'', sonst werden NUR Verzeichnisse angezeigt), und in dem man mittels des Radiobuttons auch ausschließlich Dateien auswählen kann, KEINE Unterverzeichnisse (''filesOnly =&amp;gt; true''). Zusätzlich gebe ich den &amp;quot;Basis-Pfad&amp;quot; an, aus dem man auswählen kann (''path''). Wobei der natürlich bei Jedem anders heißen kann...Also eigentlich nicht so toll. Muss nochmal drüber nachdenken.&lt;br /&gt;
&lt;br /&gt;
Noch die Palettendefinition erweitern um&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
'{beschreibung_legend:hide},beschreibung;{bild_legend:hide},bild;'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
und wir landen hier:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_014.png]]&lt;br /&gt;
&lt;br /&gt;
Damit bin ich im Prinzip mit der Maskendefinition für diese Tabelle fertig, abgesehen vom Hook für das MD5-Hashing meines Passworts. Das verschiebe ich erstmal auf später :-).&lt;br /&gt;
&lt;br /&gt;
Folgende &amp;quot;Probleme&amp;quot; habe ich noch: Meine Palettendefinition sieht insgesamt so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname;'.'{classes_legend},startgruppe,startklasselatein,startklassestandard;'.'{aktiv_legend:hide},aktiv,aktivseit,aktivbis;password_legend:hide},password;'.'{contact_legend:hide},zeigeanschrift,anschrift,zeigetelefon,telefon,zeigefax,fax,zeigemobil,mobil,zeigeemail,email,zeigehomepage,homepage;'.'{beschreibung_legend:hide},beschreibung;{bild_legend:hide},bild;' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich erwarte ich, dass nur die oberste Palette geöffnet ist, und alle folgenden geschlossen. Komischerweise sind beim Editieren bestehender Einträge und auch bei der Neuanlage alle geöffnet bis auf ''password'' und ''beschreibung''. Ich kann nicht verstehen, wieso. Kann mich jemand schlau machen?&lt;br /&gt;
&lt;br /&gt;
Die Eigenschaft ''exclude'' im Abschnitt ''fields'' soll steuern, ob das jeweilige Feld in der Usergruppenverwaltung spezifisch für einzelne Gruppen (de)aktivierbar ist. ''Bei exclude =&amp;gt; true'' soll das Feld in der Usergruppenverwaltung erscheinen, bei ''false'' soll es dort nicht erscheinen und immer sichtbar sein (für die Gruppen, die das Backend-Modul überhaupt freigegeben haben).&lt;br /&gt;
&lt;br /&gt;
Das Verhalten scheint aber ein anderes zu sein: Egal ob ich ''exclude true'' oder ''false'' zuweise, erscheint das Feld in der Usergruppenverwaltung. Nur wenn ich ''exclude'' ganz weglasse, erscheint es dort nicht. Ein Bug? Keine Ahnung. Zumindest ist es in der Referenz anders beschrieben. Da ich diese Steuerung auf Feldebene nicht brauche, sondern das ganze Backendmodul nur einer bestimmten Usergruppe freischalten möchte, habe ich die ''exclude''-Eigenschaft aus allen Felddefinitionen entfernt. &lt;br /&gt;
&lt;br /&gt;
Mein &amp;quot;Traum&amp;quot; wäre, dass man, falls ein Bild schon ausgewählt ist im Filetree man sofort dieses Bild sieht, statt erst den Filetree öffnen zu müssen, um zu sehen ob irgendwo der Radiobutton gesetzt ist. So kann man beim Öffnen eines Datensatzes nicht schnell sehen, ob ein Paar ein Bild zugewiesen hat, oder nicht. Aber ich glaube, das ist so (noch) nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
So, das sollte das Ende von Schritt 4 gewesen (puh),. Um die Maske zu vervollständigen werde ich mit der Definition der Texte in den Sprachfiles weitermachen.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-03_Backend_BE-Modul_und_SQL</id>
		<title>TEE-03 Backend BE-Modul und SQL</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-03_Backend_BE-Modul_und_SQL"/>
				<updated>2010-07-07T10:18:19Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Backe…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Backend-Modul registrieren=&lt;br /&gt;
Jetzt geht es also an die Files, die uns der ''Extension-Creator'' im letzten Schritt erzeugt hat. &lt;br /&gt;
&lt;br /&gt;
Zunächst will ich mein Backend-Modul in TYPOlight bekannt machen. Dafür öffne ich ''/system/modules/gw_turnierpaare/config/config.php''.&lt;br /&gt;
&lt;br /&gt;
Im Skelett dieser Datei sind schon Abschnitte für die Eintragung von Backend-Modulen, Front-Modulen, Content-Elementen, Hooks und noch viel mehr vorgesehen. Ich orientiere mich am [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorial] und trage im Abschnitt für Backend-Module folgendes ein:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$GLOBALS['BE_MOD']['content']['gw_turnierpaare'] = array &lt;br /&gt;
( &lt;br /&gt;
    'tables' =&amp;gt; array('tl_gw_turnierpaare','tl_gw_meldungen'), &lt;br /&gt;
    'icon'   =&amp;gt; 'system/modules/gw_turnierpaare/icons/turnierpaare.png' &lt;br /&gt;
);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hiermit registriere ich ein Modul mit dem Bezeichner ''gw_turnierpaare'', das sich auf die Datenbanktabellen ''tl_gw_turnierpaare'' und ''tl_gw_meldungen'' stützt (wie im Extension-Generator angegeben). In der Liste der Backend-Module (linke Spalte im Backend) soll ein Icon vor dem Bezeichner angezeigt werden, dessen Pfad ich unter 'icon' angegeben habe. Das Icon, was ich mir ausgesucht habe, ist an diesen Post angehängt. &lt;br /&gt;
&lt;br /&gt;
Ich habe mich für ein eigenes Unterverzeichnis für mögliche weitere Icons entschieden, und deshalb manuell das Unterverzeichnis &amp;quot;icons&amp;quot; angelegt und mein Icon dort hochgeladen. &lt;br /&gt;
&lt;br /&gt;
Im Backend-Modul soll der Berechtigte (also der Sportwart) die Daten Anlegen/Löschen/Ändern dürfen.&lt;br /&gt;
&lt;br /&gt;
Ich speichere die Datei zunächst, und lade meine Backend-Ansicht (als Administrator!) neu. Nun sehe ich in der linken Spalte unter &amp;quot;Inhalte&amp;quot; den neuen Eintrag ''gw_turnierpaare'' mit meinem Icon. Ein Klick darauf führt leider noch zu einer Fehlermeldung, da die SQL-Tabellen ''tl_gw_turnierpaare'' und ''tl_gw_meldungen'' noch nicht angelegt sind.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_001.png]]&lt;br /&gt;
==SQL-Tabellenstruktur anlegen==&lt;br /&gt;
Also, die Tabellen anlegen: Ich öffne ''/system/modules/gw_turnierpaare/config/database.sql'' , in der mir der Extension-Generator schon ein Skelett für meine beiden Tabellen vorgegeben hat. In beiden Tabellen sind ''id'', ''pid'', ''sorting'' und ''tstamp'' vorgegeben, sowie der primary key ''id'' und der key ''pid''. Ich vermute, dass ''pid'' die &amp;quot;Parent ID&amp;quot; ist. Meine Turnierpaare haben keinen parent, darum lösche ich die Definition von ''pid'' und die Festlegung von ''pid'' als Key.&lt;br /&gt;
&lt;br /&gt;
Ich füge meine restlichen Felder hinzu, ohne so recht zu wissen, mit welcher Syntax genau. Ich habe mal was von SQL92-Syntax gelesen, aber die kenne ich nicht. Gibt es BOOLEAN-Datentypen? Char vs. Varchar? Sicherheitshalber halte ich mich erstmal an die MySQL-Syntax. Im Endeffekt sieht der Abschnitt für ''tl_gw_turnierpaare'' in ''database.sql'' so aus:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE `tl_gw_turnierpaare` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `partnernachname` varchar(64) NOT NULL default '_',&lt;br /&gt;
  `partnervorname` varchar(64) NULL,&lt;br /&gt;
  `partnerinnachname` varchar(64) NULL,&lt;br /&gt;
  `partnerinvorname` varchar(64) NULL,&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '_',&lt;br /&gt;
  `startklasselatein` varchar(12) NULL,&lt;br /&gt;
  `startklassestandard` varchar(12) NULL,&lt;br /&gt;
  `aktiv` int(1) NOT NULL default '0',&lt;br /&gt;
  `aktivseit` int(4) NULL,&lt;br /&gt;
  `aktivbis` int(4) NULL,&lt;br /&gt;
  `password` varchar(32) NULL,&lt;br /&gt;
  `bild` varchar(255) NULL,&lt;br /&gt;
  `anschrift` text NULL,&lt;br /&gt;
  `zeigeanschrift` int(1) NOT NULL default '0',&lt;br /&gt;
  `telefon` varchar(32) NULL,&lt;br /&gt;
  `zeigetelefon` int(1) NOT NULL default '0',&lt;br /&gt;
  `fax` varchar(32) NULL,&lt;br /&gt;
  `zeigefax` int(1) NOT NULL default '0',&lt;br /&gt;
  `mobil` varchar(32) NULL,&lt;br /&gt;
  `zeigemobil` int(1) NOT NULL default '0',&lt;br /&gt;
  `email` varchar(128) NULL,&lt;br /&gt;
  `zeigeemail` int(1) NOT NULL default '0',&lt;br /&gt;
  `homepage` varchar(128) NULL,&lt;br /&gt;
  `zeigehomepage` int(1) NOT NULL default '0',&lt;br /&gt;
  `beschreibung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man kann sich hier jetzt beliebige Gedanken über die Datenstruktur, Abstraktion, Normalisierung usw machen. Ich möchte es jetzt '''so''' lösen.&lt;br /&gt;
&lt;br /&gt;
Meine Meldungen in ''tl_gw_meldungen'' sollen parents haben (nämlich die Turnierpaare), darum lasse ich das Skelett so, und erweitere um meine eigenen Felder. Für meinen Fall kommt das hier heraus:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE `tl_gw_meldungen` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `pid` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `datum` date NOT NULL default '1900-01-01',&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '_',&lt;br /&gt;
  `startklasse` varchar(12) NOT NULL default '_',&lt;br /&gt;
  `lat_std` char(1) NOT NULL default '_',&lt;br /&gt;
  `turnierort` varchar(128) NOT NULL default '_',&lt;br /&gt;
  `turnierart` varchar(64) NULL,&lt;br /&gt;
  `anzahlpaare` int(4) NULL,&lt;br /&gt;
  `platz_von` int(4) NULL,&lt;br /&gt;
  `platz_bis` int(4) NULL,&lt;br /&gt;
  `bemerkung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
  KEY `pid` (`pid`)&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich speichere ''database.sql'' und rufe ''/typolight/install.php'' in meiner TYPOlight-Installation auf. TYPOlight bemerkt, daß die Datenbankstruktur nicht mehr aktuell ist, und schlägt mir vor, meine Tabellen anzulegen. Ich bestätige das.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_002.png]] &lt;br /&gt;
&lt;br /&gt;
Was dann kommt, erstaunt mich dann aber doch etwas: Die Datenbankstruktur soll weiterhin nicht aktuell sein:&lt;br /&gt;
&lt;br /&gt;
[[Datei:attachment_003.png]]&lt;br /&gt;
&lt;br /&gt;
Auch wenn ich diese Vorschläge bestätige, ändert sich nichts. Ein Blick in die Datenbank zeigt aber, dass die Tabellen wie von mir gewünscht angelegt wurden. Irgendwie kommt TYPOlight dort ins Schleudern. Ein Klick auf ''gw_turnierpaare'' im Backend verläuft jetzt aber ohne Fehlermeldung, auch wenn in diesem Backend-Modul noch nichts &amp;quot;passiert&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Meine Frage an dieser Stelle also an die erfahrenen Entwickler: Was ist an meiner SQL-Definition &amp;quot;falsch&amp;quot;, dass die Tabellen zwar richtig angelegt werden, das TYPOlight-Install-Tool aber damit nicht zurecht kommt?&lt;br /&gt;
&lt;br /&gt;
==SQL reloaded==&lt;br /&gt;
Nach kleinem Kampf mit dem Install-Tool - dokumentiert in der Diskussion weiter unten - sieht das SQL für meine beiden Tabellen in ''database.sql'' nun so aus:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE `tl_gw_turnierpaare` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `partnernachname` varchar(64) NOT NULL default '',&lt;br /&gt;
  `partnervorname` varchar(64) NULL default NULL,&lt;br /&gt;
  `partnerinnachname` varchar(64) NULL default NULL,&lt;br /&gt;
  `partnerinvorname` varchar(64) NULL default NULL,&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '',&lt;br /&gt;
  `startklasselatein` varchar(12) NULL default NULL,&lt;br /&gt;
  `startklassestandard` varchar(12) NULL default NULL,&lt;br /&gt;
  `aktiv` int(1) NOT NULL default '0',&lt;br /&gt;
  `aktivseit` int(4) NULL default NULL,&lt;br /&gt;
  `aktivbis` int(4) NULL default NULL,&lt;br /&gt;
  `password` varchar(32) NULL default NULL,&lt;br /&gt;
  `bild` varchar(255) NULL default NULL,&lt;br /&gt;
  `anschrift` text NULL,&lt;br /&gt;
  `zeigeanschrift` int(1) NOT NULL default '0',&lt;br /&gt;
  `telefon` varchar(32) NULL default NULL,&lt;br /&gt;
  `zeigetelefon` int(1) NOT NULL default '0',&lt;br /&gt;
  `fax` varchar(32) NULL default NULL,&lt;br /&gt;
  `zeigefax` int(1) NOT NULL default '0',&lt;br /&gt;
  `mobil` varchar(32) NULL default NULL,&lt;br /&gt;
  `zeigemobil` int(1) NOT NULL default '0',&lt;br /&gt;
  `email` varchar(128) NULL default NULL,&lt;br /&gt;
  `zeigeemail` int(1) NOT NULL default '0',&lt;br /&gt;
  `homepage` varchar(128) NULL default NULL,&lt;br /&gt;
  `zeigehomepage` int(1) NOT NULL default '0',&lt;br /&gt;
  `beschreibung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE `tl_gw_meldungen` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `pid` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `datum` date NOT NULL default '1900-01-01',&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '',&lt;br /&gt;
  `startklasse` varchar(12) NOT NULL default '',&lt;br /&gt;
  `lat_std` char(1) NOT NULL default '',&lt;br /&gt;
  `turnierort` varchar(128) NOT NULL default '',&lt;br /&gt;
  `turnierart` varchar(64) NULL default NULL,&lt;br /&gt;
  `anzahlpaare` int(4) NULL default NULL,&lt;br /&gt;
  `platz_von` int(4) NULL default NULL,&lt;br /&gt;
  `platz_bis` int(4) NULL default NULL,&lt;br /&gt;
  `bemerkung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
  KEY `pid` (`pid`)&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
und wir merken uns:&lt;br /&gt;
&lt;br /&gt;
* NOT NULL-Felder mit default (logisch)&lt;br /&gt;
* NULL-&amp;quot;text&amp;quot;-Felder OHNE default&lt;br /&gt;
* Sonstige NULL-Felder mit &amp;quot;default NULL&amp;quot;&lt;br /&gt;
* default _KLEIN_ schreiben&lt;br /&gt;
* Und falls man da was verändert: _2_ Leerzeichen zwischen PRIMARY KEY und (`id`)&lt;br /&gt;
&lt;br /&gt;
Und hier nochmal der Link zum Thread, der das erklärt: &lt;br /&gt;
&lt;br /&gt;
[http://www.typolight-community.de/showthread.php?t=41 Tipps zur SQL Dump Syntax in TYPOlight]&lt;br /&gt;
&lt;br /&gt;
So, das Install-Tool ist zufrieden, die Datenbank-Tabellen angelegt - es kann weiter gehen!&lt;br /&gt;
&lt;br /&gt;
===Diskussionsbeiträge aus dem Forum===&lt;br /&gt;
'''user: Seitengestalter''' &lt;br /&gt;
&lt;br /&gt;
Hallo, jeweils am Ende der Zeile das &amp;gt;NULL&amp;lt; durch &amp;gt;''&amp;lt; (das sind zwei einfache Striche, nicht der Doppelte - und ohne die spitzen Klammern) ersetzen.&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
leider Nein...&lt;br /&gt;
Das Install-Tool schlägt dann ein Anpassen der Datenbankstruktur z.B. wie folgt vor:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `tl_gw_turnierpaare` CHANGE `partnervorname` `partnervorname` varchar(64) '';&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn man das bestätigt, erntet man nur eine SQL-Fehlermeldung (von MySQL).&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Fatal error: Uncaught exception Exception  with message Query error: You have an error in &lt;br /&gt;
your SQL syntax; check the manual that corresponds to your MySQL server version for the &lt;br /&gt;
right syntax to use near '''' at line 1 (ALTER TABLE `tl_gw_turnierpaare` CHANGE &lt;br /&gt;
`partnervorname` `partnervorname` varchar(64) '';)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Noch jemand eine Idee?&lt;br /&gt;
&lt;br /&gt;
Im o.g. [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorial] wird es in einer Zeile der database.sql bei einem NULL-Feld auch so gemacht &lt;br /&gt;
(also mit &amp;quot;NULL&amp;quot; am Ende der Zeile). Lasse ich &amp;quot;NULL&amp;quot; komplett weg, will mir das Installationstool weiterhin die &lt;br /&gt;
Datenbankstruktur anpassen, obwohl sie eigentlich schon korrekt ist.&lt;br /&gt;
&lt;br /&gt;
'''user: Seitengestalter''' &lt;br /&gt;
&lt;br /&gt;
Sorry, mein Fehler. Muss heißen &amp;gt;default ''&amp;lt;.&lt;br /&gt;
Meiner Erfahrung nach mag Tl kein varchar mit dem Default NULL &lt;br /&gt;
&lt;br /&gt;
'''user: BugBuster''' &lt;br /&gt;
&lt;br /&gt;
Siehe hier zum Thema &amp;quot;wie erstelle ich die sql richtig&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[http://www.typolight-community.de/showthread.php?t=41 Tipps zur SQL Dump Syntax in TYPOlight]&lt;br /&gt;
&lt;br /&gt;
Vereinfacht gesagt, vollständige MySQL Syntax. &lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
OK, wir kommen der Sache näher, aber für mich bleibt es mysteriös...&lt;br /&gt;
* NOT NULL Felder sind kein Problem - Man gibt den Default an, und alles ist OK.&lt;br /&gt;
* varchar-Felder mit NULL werden geschluckt (also funktionieren), wenn man &amp;quot;default ''&amp;quot; anhängt, also &lt;br /&gt;
z.b.&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`name` varchar(32) NULL default ''&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* int- oder text-Felder mit NULL werden vom Install-Tool nicht geschluckt, wenn &amp;quot;default '0'&amp;quot; (für int) &lt;br /&gt;
oder &amp;quot;default ''&amp;quot; (für text) anhängt, also z.B.&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`flag` int(1) default '0'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Install-Tool meint weiterhin, die Datenbankstruktur würde nicht stimmen, und lässt sich auch nicht davon &lt;br /&gt;
abhalten.&lt;br /&gt;
&lt;br /&gt;
Ich habe mal in das database.sql der Extension &amp;quot;twitterreader&amp;quot; geschaut, dort steht ein NON-NULL text-Feld als&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`feld` text NULL,&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
eingetragen, und dort funktioniert das offensichtlich auch. Warum bei mir nicht? Help!&lt;br /&gt;
&lt;br /&gt;
P.S.: Meine verbleibenden Problem-Felder sind:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `tl_gw_turnierpaare` CHANGE `aktivseit` `aktivseit` int(4) NULL default '0000';&lt;br /&gt;
ALTER TABLE `tl_gw_turnierpaare` CHANGE `aktivbis` `aktivbis` int(4) NULL default '0000';&lt;br /&gt;
ALTER TABLE `tl_gw_turnierpaare` CHANGE `anschrift` `anschrift` text NULL default '';&lt;br /&gt;
ALTER TABLE `tl_gw_turnierpaare` CHANGE `beschreibung` `beschreibung` text NULL default '';&lt;br /&gt;
ALTER TABLE `tl_gw_meldungen` CHANGE `bemerkung` `bemerkung` text NULL default '';&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''user: BugBuster'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 Zitat von Seitengestalter   &lt;br /&gt;
 Meiner Erfahrung nach mag Tl kein varchar mit dem Default NULL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Doch, sieht komisch aus, aber so gehts:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 `varchar_null_demo` varchar(32) NULL default NULL,&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 Siehe Link von mir weiter oben.&lt;br /&gt;
 &lt;br /&gt;
'''user: BugBuster''' &lt;br /&gt;
&lt;br /&gt;
 Mal einfach gefragt, wenn ein Feld NULL sein darf, wozu dann ein Default? &lt;br /&gt;
 Wenn ein Default eingetragen werden soll, wenn nichts übergeben wurde, dann muss NOT NULL definiert werden.&lt;br /&gt;
 Textfelder dürfen kein Default haben, bei INT und NULL gilt: &lt;br /&gt;
&lt;br /&gt;
 Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 ALTER TABLE `tl_gw_turnierpaare` CHANGE `aktivseit` `aktivseit` int(4) NULL default NULL;&lt;br /&gt;
 ALTER TABLE `tl_gw_turnierpaare` CHANGE `aktivbis` `aktivbis` int(4) NULL default NULL;&lt;br /&gt;
 ALTER TABLE `tl_gw_turnierpaare` CHANGE `anschrift` `anschrift` text NULL;&lt;br /&gt;
 ALTER TABLE `tl_gw_turnierpaare` CHANGE `beschreibung` `beschreibung` text NULL;&lt;br /&gt;
 ALTER TABLE `tl_gw_meldungen` CHANGE `bemerkung` `bemerkung` text NULL;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
Halleluja, es ist gelöst!&lt;br /&gt;
&lt;br /&gt;
Wenn man genau nach [http://www.typolight-community.de/showthread.php?t=41 Tipps zur SQL Dump Syntax in TYPOlight]&lt;br /&gt;
 arbeitet, dann geht es:&lt;br /&gt;
&lt;br /&gt;
* NOT NULL-Felder mit default&lt;br /&gt;
* NULL-Felder mit &amp;quot;NULL default NULL&amp;quot;&lt;br /&gt;
* NULL-text-Felder ohne default!&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
 Zitat von BugBuster   &lt;br /&gt;
Mal einfach gefragt, wenn ein Feld NULL sein darf, wozu dann ein Default?&lt;br /&gt;
Einfache Antwort: Weil Roland mich drauf brachte und es (komischerweise) funktioniert. Ich hätte mir sowas &lt;br /&gt;
nicht ausgedacht ;-). &amp;quot;NULL default NULL&amp;quot; ist aber auch eine gewisse Tautologie. Anyway, es funktioniert...und &lt;br /&gt;
&amp;quot;NULL default NULL&amp;quot; gefällt mir auch besser, darum habe ich es jetzt darauf geändert.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-14_Downloads</id>
		<title>TEE-14 Downloads</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-14_Downloads"/>
				<updated>2010-07-07T10:10:42Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Downl…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Downloads=&lt;br /&gt;
dl1ely hat eine gezippte Version seiner Extension zum Download zur Verfügung gestellt, der Stand ist vom 29.05.2010. &lt;br /&gt;
Diese Datei entpacken Sie bitte in den TL/contao-Ordner ''/system/modules/'' und rufen dann das TL/contao-Installationstool auf. &lt;br /&gt;
&lt;br /&gt;
[http://dl.dropbox.com/u/804662/gw_turnierpaare_20100529.zip Quelltext des Moduls]&lt;br /&gt;
&lt;br /&gt;
Schnippsel hat aus den Forumsbeiträgen bis #104 eine PDF-Datei erstellt, die minimal gekürzt ist. Insbesondere alle forumsspezifischen Details (z.B. Fotos der Poster etc.), Anreden und Grußformeln sowie die Lobeshymnen (&amp;quot;Ich finde dein Tutorial gaaaaaanz toll!&amp;quot;) wurden entfernt. Trotzdem hat die Datei eine Größe von ca. 1,5 MB und umfasst ca. 125 Seiten!&lt;br /&gt;
&lt;br /&gt;
[[http://de.contaowiki.org/images/de/d/d2/Tagebuch_einer_Extension-Entwicklung_-_bis_104.pdf PDF-Datei mit Forumsbeiträgen]]&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-15_Werkzeuge</id>
		<title>TEE-15 Werkzeuge</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-15_Werkzeuge"/>
				<updated>2010-07-07T10:08:36Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Werkz…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Werkzeuge=&lt;br /&gt;
==Lokaler Webserver / lokale MySQL-Datenbank==&lt;br /&gt;
&lt;br /&gt;
==Editor==&lt;br /&gt;
* PSPad ist ein besonders auf Programmierer und Webdesigner zugeschnittener unicode-fähiger Editor für Microsoft Windows mit den folgenden Merkmalen:&lt;br /&gt;
&lt;br /&gt;
** Einfaches Arbeiten mit verschiedenen Entwicklungsumgebungen&lt;br /&gt;
** Farbig hervorgehobene Syntax für viele Programmiersprachen, HTML usw. (erweiterbar)&lt;br /&gt;
** HTML-Vorschau mit einem Tastendruck&lt;br /&gt;
** Geringe Dateigröße, gekoppelt mit dem Funktionsumfang eines professionellen Editors&lt;br /&gt;
** Einfaches Arbeiten mit Textdateien&lt;br /&gt;
&lt;br /&gt;
Näheres siehe unter [http://www.pspad.com/de/ PSPad]&lt;br /&gt;
&lt;br /&gt;
* Notepad++&lt;br /&gt;
&lt;br /&gt;
==Bildbearbeitungsprogramm==&lt;br /&gt;
==FTP-Programm==&lt;br /&gt;
* WinSCP ist ein grafischer Open Source SFTP und FTP Client für Windows, der auch das alte SCP-Protokoll unterstützt. Er bietet einen geschützten Daten- und Dateitransfer zwischen verschiedenen Rechnern und ermöglicht die Nutzung geschützter &amp;quot;Tunnel&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
WinSCP kann alle grundlegenden Operationen mit Dateien, wie downloaden und uploaden,  erledigen. Es kann auch Dateien &amp;amp; Ordner umbenennen, neue Ordner erstellen, Eigenschaften von Dateien &amp;amp; Ordnern ändern, und symbolische Links und Verknüpfungen erstellen.&lt;br /&gt;
&lt;br /&gt;
Eine der beiden zur Auswahl stehenden Programm-Oberflächen erlaubt dem Benutzer das Managen von Dateien sogar auf dem lokalen Computer. &lt;br /&gt;
&lt;br /&gt;
Näheres siehe unter [http://winscp.net/eng/docs/lang:de Was ist WinSCP]&lt;br /&gt;
&lt;br /&gt;
* FileZilla&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-02_Extension_Creator</id>
		<title>TEE-02 Extension Creator</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-02_Extension_Creator"/>
				<updated>2010-07-07T10:07:08Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Exten…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Extension-Creator=&lt;br /&gt;
Ich verwende den [http://www.contao.org/erweiterungsliste/view/development.de.html Extension-Creator] aus dem Extension-Repository. Der ''Extension-Creator'', ehemals: ''Module Creator'', wurde von Leo Fey programmiert, war ursprünglich Teil des TL-Cores und wurde dann in eine separate Extension ausgelagert. Sie müssen den ''Extension-Creator'' also zunächst aus dem Repository installieren. Er firmiert im Repository allerdings nicht als ''Extension-Creator'', sondern als ''development''!&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea01.png]]&lt;br /&gt;
&lt;br /&gt;
Der ''Extension-Creator'' erscheint dann in der Dateistruktur unter ''tl/system/modules/development'' und in der Sidebar des Backends unter ''System''.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea02.png]]&lt;br /&gt;
&lt;br /&gt;
Also, los geht es mit dem Skelett für die geplante Extension.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea03.png]]&lt;br /&gt;
&lt;br /&gt;
* Titel: Es geht um Turnierpaar-&amp;quot;Verwaltung&amp;quot;, und um Namenskonflikte zu vermeiden möchte ich gerne einen spezifischen Präfix nutzen: ''gw'' angelehnt an den Vereinsnamen &amp;quot;Grün-Weiß&amp;quot;. Also: Titel = ''gw_turnierpaare''. An dieser Stelle bin ich mir noch nicht so sicher, wo dieser &amp;quot;Titel&amp;quot; überall erscheinen wird, und ob es deshalb ein beliebiger Text sein soll, oder eher ein &amp;quot;identifier&amp;quot;, also z.b. ohne Leerzeichen u.ä. Sicherheitshalber gehe ich den Identifier-Weg. Besser hässlich als nicht-funktionierend.&lt;br /&gt;
&lt;br /&gt;
* Ordnername: Ebenfalls ''gw_turnierpaare''.&lt;br /&gt;
&lt;br /&gt;
* Autor, Copyright und Lizenz: Selbsterklärend&lt;br /&gt;
&lt;br /&gt;
* Paket: Ein Paketname ist gefragt. Der Hilfetext unter dem Eingabefeld schlägt hilfreich &amp;quot;z.B. meinEigenesModul&amp;quot; vor. Ist das Modul jetzt das Paket? Was ist ein Paket? Sowas wie ein Namensraum? Da ich noch nicht weiß, ob ich für die Vereinsseite noch andere Extensions pogrammieren werde, nehme ich die Vereinsabkürzung als &amp;quot;Paketname&amp;quot;, also ''GW''. Weitere vereinsspezifische Extensions würde ich dann in dasselbe Paket stecken.&lt;br /&gt;
&lt;br /&gt;
* Ein Backend-Modul hinzufügen: Ja klar, schließlich sollen Daten im Backend bearbeitet werden. Also dort ein Häkchen.&lt;br /&gt;
&lt;br /&gt;
* Backend-Klassen: Wenig hilfreicher Erklärungstext: &amp;quot;Hier können Sie eine kommagetrennte Liste der zu erstellenden Backend-Klassen eingeben.&amp;quot; - Was sind Backend-Klassen? Wofür brauche ich die? Eigentlich müsste doch alles, was ich im Backend vorhabe, durch Einträge im DCA-File realisierbar sein, schließlich geht es nur um Pflege von zwei abhängigen Datenbanktabellen. Also mal mutig leer gelassen, falls das falsch ist kann man es später noch hinzufügen.&lt;br /&gt;
&lt;br /&gt;
* Backend-Tabellen: Das sind wohl meine Datentabellen, ich will eine für Turnierpaare, eine für Meldungen, also: ''tl_gw_turnierpaare,tl_gw_meldungen''.&lt;br /&gt;
&lt;br /&gt;
* Backend-Templates: Auch hier wieder wenig erhellender Hilfetext. Auch das TL-Buch beschränkt sich da leider fast auf das Abschreiben der Hilfetexte unter den Eingabefeldern. Ich kenne Templates nur für das Frontend, also beschließe ich mutig, dass ich das wohl nicht brauche. Sollte sich das später als Irrtum herausstellen, wird es sich hoffentlich noch korrigieren lassen.&lt;br /&gt;
&lt;br /&gt;
* Ein Frontend-Modul hinzufügen: Aber klar, die Daten sollen schließlich im Frontend visualisiert werden. Also Haken dran.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Klassen: So weit wie ich es bisher verstanden habe, braucht jedes Modul eine eigene Klasse. Nach meiner bisherigen Planung brauche ich ein Modul ''Turnierpaarliste'' inklusive Detail-Ansicht der einzelnen Paar-Einträge. Die Unterscheidung aktiv/nicht aktiv würde ich gerne über einen Parameter im Modul lösen, so dass dasselbe Modul die Liste der aktiven und der ehemaligen Paare anzeigen kann. Außerdem benötige ich ein Modul ''Meldeliste'' mit der chronologisch sortierten Übersicht der Meldungen. Also: ''gwTurnierpaarliste,gwMeldeliste'' als Klassennnamen.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Tabellen: Ratlosigkeit. Was unterscheidet Frontend-Tabellen von Backend-Tabellen? Da ich meine Tabellen schon in den Backend-Tabellen abgehandelt habe, lasse ich das Feld leer.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Templates: Natürlich! ''gw_turnierpaarliste,gw_turnierpaarliste_detail,gw _meldeliste'' fallen mir sofort ein, vielleicht genügt das schon. Falls nicht, kann ich später noch welche hinzufügen.&lt;br /&gt;
&lt;br /&gt;
* Sprachpakete erstellen: Natürlich. Auch wenn es wahrscheinlich niemand in Englisch benutzen wird, tut es mir aber auch nicht weh, also Sprachen = ''en,de''.&lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea04.png]]&lt;br /&gt;
&lt;br /&gt;
Dann &amp;quot;speichern und schließen&amp;quot;, und auf den grünen Haken am Ende der neuen Zeile ''gw_turnierpaare'' im Extension-Creator geklickt. &lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea05.png]]&lt;br /&gt;
&lt;br /&gt;
Die Warnung bestätigt, &lt;br /&gt;
&lt;br /&gt;
[[Datei:ext_crea06.png]]&lt;br /&gt;
&lt;br /&gt;
und der Extension-Creator hat mir erstmal den Grundstock an Files in ''/system/modules/gw_turnierpaare/'' erzeugt. Und zwar:&lt;br /&gt;
&lt;br /&gt;
* ''gwMeldeliste.php,gwTurnierpaarliste.php'': meine Frontendklassen&lt;br /&gt;
&lt;br /&gt;
* ''config/config.php'' und ''config/database.sql'' (Letzteres für meine SQL-Tabellenstruktur)&lt;br /&gt;
&lt;br /&gt;
* ''dca/tl_gw_turnierpaare.php'' und ''dca/tl_gw_meldungen.php'': Die DCA-Definitionen für meine Tabellen zur Bearbeitung im Backend&lt;br /&gt;
&lt;br /&gt;
* ''languages/...'': Die Sprachfiles in en und de-Variante&lt;br /&gt;
&lt;br /&gt;
* ''templates/...'': Die drei Frontend-Templates, die ich angegeben hatte&lt;br /&gt;
&lt;br /&gt;
Im nächsten Schritt orientieren wir uns etwas und beginnen, die vorgegebenen Files zu modifizieren.&lt;br /&gt;
&lt;br /&gt;
P.S.: Wenn die erfahrenen TL-Programmierer jetzt schon Gänsehaut haben: Sorry. Ich mache das zum ersten &lt;br /&gt;
Mal, und stelle mich nicht künstlich dumm an. Ich versuche so zu schildern, wie ich als Einsteiger die Sachen &lt;br /&gt;
sehe, was mich verwirrt usw...Bin für Verbesserungsvorschläge z.B. zu Namens-Schemata usw immer zu haben. &lt;br /&gt;
Genauso freue ich mich über Aufklärung zu Dingen, die ich selbst nicht verstehe...Backendklassen, Backend-&lt;br /&gt;
Templates, Frontend-Tabellen, Paket...&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-01_Einleitung</id>
		<title>TEE-01 Einleitung</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-01_Einleitung"/>
				<updated>2010-07-07T09:57:41Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: Die Seite wurde neu angelegt: „{{stub}} Tagebuch einer Extension-Entwicklung Category:Tagebuch_einer_Extension-Entwicklung {{AppliesTo |Ext1=Extension Creator |TLVersion=ab TL 2.8}}  =Allge…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Allgemeine Hinweise=&lt;br /&gt;
Ich möchte hier gerne eine Art &amp;quot;Tagebuch&amp;quot; einer Extension-Entwicklung schreiben. Ich möchte mit diesem Tagebuch anderen &amp;quot;Anfängern&amp;quot; die Möglichkeit geben, an einem realen Beispiel zu lernen, und auch meine Entscheidungen und Gedanken entlang des Wegs kennen zulernen. &lt;br /&gt;
&lt;br /&gt;
In vielen Tutorials wird nur vorgegeben, was in welche Datei geschrieben wird, und was Zeile X oder Zeile Y dort tut. Der Prozess hin zu Zeile X oder Y bleibt leider zu oft im Dunkeln, und erschwert mir die Übertragung der vorgestellten Tutorial-Inhalte auf meine eigenen Probleme. &lt;br /&gt;
&lt;br /&gt;
Ich möchte hier auch Irrwege dokumentieren, wie sie für Extension-Anfänger wahrscheinlich typisch sind, und nicht nur ein Tutorial zum Endprodukt abliefern. &lt;br /&gt;
&lt;br /&gt;
Was bringe ich mit?&lt;br /&gt;
&lt;br /&gt;
* Ich bin PHP-erfahren, habe aber noch nie eine TL-Extension geschrieben. &lt;br /&gt;
* Ich besitze das TL-Buch, [http://www.contao.org/buecher-und-videos.html Das offizielle TYPOlight-Handbuch], &lt;br /&gt;
* ich kenne das [http://dev.contao.org/projects/typolight/wiki/TutorialsHalloWeltExtension Hello, World]-Beispiel, &lt;br /&gt;
* ich kenne das [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorial], &lt;br /&gt;
* ich kenne das [http://www.contao.org/tl_files/meetings/Modulentwicklung.pdf FlowPlayer-Beispiel].&lt;br /&gt;
 &lt;br /&gt;
Trotzdem ist mir weiterhin nicht glasklar, welche Schritte man bis zur eigenen Extension gehen muss.&lt;br /&gt;
&lt;br /&gt;
Vorneweg:&lt;br /&gt;
&lt;br /&gt;
TL = TYPOlight&lt;br /&gt;
FE = Frontend (Seite, die jeder Surfer sieht)&lt;br /&gt;
BE = Backend (Seite, die nur eingeloggte &amp;quot;Redakteure&amp;quot; sehen unter der /typolight URL)&lt;br /&gt;
&lt;br /&gt;
Ich verwende folgende Tools:&lt;br /&gt;
&lt;br /&gt;
* WinSCP unter Windows 7 und &lt;br /&gt;
* PSPad als Editor.&lt;br /&gt;
&lt;br /&gt;
Siehe dazu auch [[TEE-15-Werkzeuge | TEE-15-Werkzeuge]].&lt;br /&gt;
&lt;br /&gt;
Alles soll sich unter TL 2.8.0 abspielen, und ich werde den [http://www.contao.org/erweiterungsliste/view/development.de.html Extension-Creator] verwenden, um mir das &amp;quot;Skelett&amp;quot; der Extension zu erstellen.&lt;br /&gt;
&lt;br /&gt;
Die Extension wird sehr speziell auf die Bedürfnisse der von mir betreuten Seite zugeschnitten sein. Ich glaube nicht, dass mit dem engen Scope jemand anders sie nutzen kann. Darum werde ich sie wohl auch nicht im Extension-Repository veröffentlichen.&lt;br /&gt;
&lt;br /&gt;
=Anforderungen und Randbedingungen=&lt;br /&gt;
Zunächst mal zum Hintergrund:&lt;br /&gt;
&lt;br /&gt;
Ich bin Webmaster der Seite http://www.gruen-weiss-aachen.de , der Webpräsenz des momentan größten Tanzsportvereins in NRW, und einem der größten in Deutschland. Wie man unschwer erkennen kann, bedarf die Seite dringend eines Relaunchs, der auf Basis von TYPOlight erfolgen soll. Dazu erfolgt auf einer Subdomain parallel zum weiteren Betrieb der bisherigen Webseite der Aufbau einer TL-basierten Seite.&lt;br /&gt;
 &lt;br /&gt;
Das Design steht noch nicht, erstmal soll die technische Funktionalität geschaffen werden. 95% der bisherigen Seiteninhalte lassen sich mit &amp;quot;TL-Bordmitteln&amp;quot; oder schon verfügbaren Extensions wie ''efg'' erschlagen. Allerdings gibt es auf der alten Seite einige &amp;quot;handgestrickte&amp;quot; PHP-Skripte, deren Funktionalität mehr oder weniger auf der neuen Seite erhalten bleiben soll.&lt;br /&gt;
&lt;br /&gt;
Eine Funktionalität, die sich mit verfügbaren Extensions meiner Meinung nach nicht nachbilden lässt, und für die ich deshalb eine eigene Extension entwickeln möchte/muss, ist folgende:&lt;br /&gt;
&lt;br /&gt;
Der Verein besitzt eine Menge an Tanzturnierpaaren. Zu diesen Turnierpaaren gehören Daten wie Name(n), Start- und Alterklassen, und ein Flag, ob das Paar noch aktiv ist. Diese Daten werden von einer berechtigten Person (Sportwart) im BE gepflegt.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich gehört zu einem Turnierpaar eine Art &amp;quot;Visitenkarte&amp;quot; mit Bild, Freitext, Email-Adresse, Telefonnummer...Diese Daten sollen auch im Backend pflegbar sein, zusätzlich sollen diese Daten aber auch von dem Turnierpaar selbst unter Kenntnis eines individuellen Passworts veränderbar sein. Dazu möchte ich aber KEINE Frontend-User-Verwaltung nutzen.&lt;br /&gt;
 &lt;br /&gt;
Für jedes Turnierpaar gibt es N &amp;quot;Meldungen&amp;quot;, dies sind Datensätze, die enthalten, zu welchem Tanzturnier ein Paar fahren wird/gefahren ist. Turnierpaare informieren den Sportwart darüber, bei welchen Turnieren sie starten wollen. Der Sportwart führt die Anmeldung beim Turnierveranstalter durch (So ist das Procedere im Tanzsport), und trägt danach die &amp;quot;Meldung&amp;quot; in der Datenbank ein. Auf der sog. &amp;quot;Meldeliste&amp;quot; kann das Tanzpaar dann selbst sehen, ob es zu einem Turnier gemeldet worden ist. Die Liste der Meldungen (1:N-Beziehung zu den Turnierpaaren) wird vom Sportwart im BE gepflegt. Auch hier gibt es die Möglichkeit, dass ein Turnierpaar unter Kenntnis seines Passworts seinen erzielten Platz auf einem Turnier und einen freien Kommentar zu einer Meldung hinzufügen kann.&lt;br /&gt;
 &lt;br /&gt;
Sollte das Tanzpaar das Turnier seiner Leistungsklasse gewonnen haben, darf es direkt im Anschluss das Turnier der nächsthöheren Klasse mittanzen (Ohne Meldung durch den Sportwart). Hier muss es die Möglichkeit geben, dass das Paar selbst einen Meldungs-Eintrag in der Datenbank vornehmen kann (Das sog. Folgeturnier).&lt;br /&gt;
 &lt;br /&gt;
Die Meldeliste dient also mehreren Zwecken:&lt;br /&gt;
&lt;br /&gt;
* Rückmeldung vom Sportwart an die Paare, dass die Meldung beim Veranstalter erfolgt ist&lt;br /&gt;
* Außenwirkung für den Verein: Wie viele Paare haben wir, und wo starten sie&lt;br /&gt;
* Außenwirkung für die Tanzpaare selbst: Wie gut haben wir abgeschnitten&lt;br /&gt;
&lt;br /&gt;
Übertragen auf die Tabellenstruktur handelt es sich also um die Tabelle der Turnierpaare, klassisch im BE durch ein BE-Modul gepflegt. Die Meldungen sind &amp;quot;Childs&amp;quot; der Turnierpaare, und sollten so auch im Backend angezeigt werden (Wie Artikel - Inhaltselemente). Zugriff auf das BE-Modul hat nur der Sportwart.&lt;br /&gt;
 &lt;br /&gt;
Zusätzlich soll es einen Mechanismus geben, unter Angabe eines Tanzpaar-spezifischen Passworts bestimmte Felder in der Tanzpaar-Tabelle und in der Melde-Tabelle durch ein Frontend-Formular zu verändern. Außerdem soll es die Möglichkeit geben, einen neuen Satz in der Melde-Tabelle anzulegen.&lt;br /&gt;
 &lt;br /&gt;
Die Ausgabe der Daten im Frontend soll auf verschiedene Weisen geschehen:&lt;br /&gt;
&lt;br /&gt;
* Modul ''Aktive Turnierpaare''&lt;br /&gt;
* Modul ''Ehemalige Turnierpaare''&lt;br /&gt;
&lt;br /&gt;
Für beide Module jeweils eine Detail-Ansicht des gewählten Turnierpaares mit Bild, Freitext, freigegebenen Kontaktdaten wie Telefon oder Email, und einer Liste aller Meldungen dieses Paares.&lt;br /&gt;
&lt;br /&gt;
* Modul ''Meldeliste'' - Eine chronologisch absteigend sortierte Liste aller Melde-Einträge, Neueste also zuerst.&lt;br /&gt;
* Module/Formulare für Änderung der Paardaten im Frontend und zum Hinzufügen von Platzierung/Kommentar bei Meldungen&lt;br /&gt;
&lt;br /&gt;
Da das Ergänzen/Ändern der einzelnen Tabellenfelder mithilfe des Paar-Passworts ohne die Einführung von Frontend-Usern doch ziemlich an der TL-Philosophie vorbeigeht, tendiere ich momentan dazu, dafür Formulare zu verwenden, deren Weiterleitungsziel eine Seite ist, die per insert-Tag ein stand-alone-PHP-File einbindet, was nach Prüfung des Passworts die entsprechenden Datenbankfelder updatet.&lt;br /&gt;
&lt;br /&gt;
Gibt es hier eigentlich Erfahrungen mit zeitgleichem Zugriff auf Tabellen bei zwei eingeloggten BE-Usern, oder wie hier in meinem Fall, wenn ein Skript auf FE-Seite potentiell Daten in der Datenbank ändert, die vielleicht gerade ein BE-User betrachtet? Aber damit werde ich leben, die Kollisionswahrscheinlichkeit ist sehr gering.&lt;br /&gt;
&lt;br /&gt;
Coming up next: Extension-&amp;quot;Skelett&amp;quot; anlegen mit dem ''Extension-Creator''. Leider komme ich momentan nicht dazu, diesen Thread täglich weiterzuführen, es ist nur Hobby. Aber ich mache weiter, keine Sorge :-).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Diskussion im Forum==&lt;br /&gt;
'''user: deerwood'''&lt;br /&gt;
 &lt;br /&gt;
kannst Du bitte begründen, warum Du die Frontend-Benutzer/Member Funktionalität nicht nutzen willst? Ich sähe nämlich (aus der Hüfte) in etwa dies Datenmodell:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
+-------------+ 1    N +--------+        +-----------+        +-----------+&lt;br /&gt;
|             |-------&amp;lt;|        |        |           |        |           |&lt;br /&gt;
|             |  Mann  |        | 1    N |           | N    1 |           |&lt;br /&gt;
|  tl_member  |        |  Paar  |-------&amp;lt;|  Meldung  |&amp;gt;-------|  Turnier  |&lt;br /&gt;
|             |  Frau  |        |        |           |        |           |&lt;br /&gt;
|             |-------&amp;lt;|        |        |           |        |           |&lt;br /&gt;
+-------------+ 1    N +--------+        +-----------+        +-----------+&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dann könnte man z.B. leicht prüfen, ob ein angemeldeter FE Nutzer Felder eines Paar-Datensatzes bearbeiten darf usw.: seine ID muss == Mann/Frau ID sein. Direkte Personendaten wären in tl_member, nur echte Paardaten wären in Paar. Turnierdaten (Termin, Ort usw.) wären sauber/normalisiert in Turnier, Meldung enthielte nur noch wenig, wie etwa Anmeldetermin, Anmelder (Sportwart oder Paar-Partner), erreichter Platz. In Tabelle Turnier könnte man auch eine Selbstreferenz auf das Folgeturnier haben und so verhindern, dass Paar-Partner sich selbst für beliebige Turniere anmelden. Man könnte auch herausbekommen, wenn Partner im Laufe der Zeit in verschiedenen Paarungen tanzen.&lt;br /&gt;
&lt;br /&gt;
Eventuell könnte man diese Erweiterung auch generalisieren: statt &amp;quot;Paar&amp;quot; etwa &amp;quot;Mannschaft/Gruppe&amp;quot; und nicht 2 Verweise auf tl_member, sondern ein serialisiertes Array mit Mitgliedern und ihrer Rolle in der Mannschaft (Mann/Frau, Torwart, Schlagzeuger, Vorschoter) und z.B. dem Start/Ende-Datum der Mitgliedschaft in der Gruppe ... oder klassisch sogar eine N:M Tabelle zwischen tl_member und &amp;quot;Mannschaft/Gruppe&amp;quot;. Besonderheiten wie &amp;quot;Anmeldung normalerweise nur durch den Sportwart&amp;quot; könnte man eventuell in eine Erweiterung zum Modul auslagern (Hook vorsehen bei der Rechteprüfung z.B.), dann hätte man ein Basismodul, das auch andere verwenden können und eben eine Tanzturnier-Speziallösung. &lt;br /&gt;
&lt;br /&gt;
Ich will nicht unnötig verkomplizieren, aber ich denke man sollte im Vorfeld schon versuchen, das Modul wiederverwendbar auszulegen und möglichst auf das TL Framework setzen.&lt;br /&gt;
&lt;br /&gt;
Nochmals etwas weiter gedacht:&lt;br /&gt;
&lt;br /&gt;
Mitglieder-Gruppen (tl_member_group) gibt es ja schon in TL mit allem Drum und Dran / Verwaltung. Vielleicht muss man für Mannschaften/Paare nur noch einige Felder und Logik ergänzen?&lt;br /&gt;
&lt;br /&gt;
Und was sind denn Turniere/Veranstaltungen? Das sind doch &amp;quot;Events&amp;quot; (tl_calendar_events), für die es ein Basis-Modul in TL gibt, und, soweit ich sehen kann, auch schon diverse Erweiterungen, die zusätzliche Felder bieten.&lt;br /&gt;
&lt;br /&gt;
Was fehlt also noch? Eigentlich nur die &amp;quot;Mitte&amp;quot; (Meldung) zwischen member_group und calendar_event.&lt;br /&gt;
&lt;br /&gt;
Das ist halt eine zusätzliche/besondere Beziehung/Relation zwischen member_group und calendar_event, die eine zusätzliche Logik erfordert, sobald jemand die Beziehung herstellen/bearbeiten möchte, implementiert als Modul (und wohl mit einer zusätzlichen N:M Tabelle &amp;quot;Meldung/Teilnahme&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Bin ich abgeflogen, oder versteht jemand diesen Ansatz oder bin ich einfach dumm und alle machen das bereits so?&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely''' &lt;br /&gt;
&lt;br /&gt;
vielen Dank für deinen Input. Habe ihn gestern Abend noch gelesen, aber keine Zeit/Ruhe zum Antworten gehabt. Prinzipiell hast du mit deiner Idee sicherlich recht, auch wenn ich aufgrund von (Noch-)Unkenntnis der schon implementierten Tabellenstruktur nicht sagen kann, ob da irgendwo noch ein Haken ist. Für ein abstraktes &amp;quot;Lehrbuchbeispiel&amp;quot; einer Extension wäre das wohl genau der richtige Weg.&lt;br /&gt;
 &lt;br /&gt;
Folgende Gründe (Die alle nicht &amp;quot;zwingend&amp;quot; sind, aber die Summe macht es) machen es aber für mich unattraktiv:&lt;br /&gt;
&lt;br /&gt;
* Eine Normalisierung in Meldung und Turnier ist in 90% der Fälle Overkill. Häufig gibt es zu einem Turnier genau eine Meldung. Häufig wird es sich also um eine 1:1-Beziehung handeln.&lt;br /&gt;
&lt;br /&gt;
* Handling der &amp;quot;Personen&amp;quot; als Front-Member: Werde ich mir nochmal anschauen, aber ein großes Erbe in meinem konkreten Fall ist leider die Notwendigkeit, schon bestehende Daten zu migrieren, insbesondere die Liste der Turnierpaare, die bis in die 90er Jahre zurückreicht. Man kann sich vorstellen, dass da bei aktuell 45 Turnierpaaren (=90 Personen AKTIV) über die Jahre geschätzt 300-400 beteiligte Personen angesammelt haben, die ich alle in die tl_member-Tabelle migrieren müsste, obwohl davon eben nur 90 überhaupt noch potentiell einloggen.&lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;Alten&amp;quot; nutzen die Seite eh nicht mehr, sollen sowieso nicht mehr ihre alten Einträge editieren dürfen, und sind (ehrlich gesagt) inzwischen teilweise verstorben. Für einen Großteil der Personen, die (inaktive) Paare bilden, müsste ich aus dem alten &amp;quot;Paar&amp;quot;-Datensatz zwei Datensätze für die tl_member-Tabelle erstellen, und mir dabei größtenteils die Inhalte der Datenfelder (email, passwort, whatever) ausdenken. &lt;br /&gt;
&lt;br /&gt;
Natürlich sehe ich die von dir geschilderten Vorteile der Abstraktion/Normalisierung, der Verfolgbarkeit des Wechsels von Paarzusammenstellungen, usw...Aber ich erkaufe es mir auch mit dem oben geschilderten Overhead.&lt;br /&gt;
&lt;br /&gt;
* Im Tanzpaar übernimmt meistens einer das Eintragen der Ergebnisse (meist der Herr :-). Wenn ich die Damen auch als Member anlegen würde, würden 45% der Member-Einträge selbst der aktiven Paare wahrscheinlich nie genutzt werden.&lt;br /&gt;
&lt;br /&gt;
* Vorschlag der Generalisierung: Sicherlich erstrebenswert, aber ich sehe die Gefahr, mich vor lauter Generalisierung &amp;quot;zu verzetteln&amp;quot;, und 90% meiner Arbeit in &amp;quot;what-ifs&amp;quot; zu stecken, die in meinem Fall gar nicht benötigt werden. &lt;br /&gt;
&lt;br /&gt;
Wenn ich mir den Source der efg-Extension angucke, die ja eine eierlegende Wollmilchsau ist, dann wird mir schwindelig, obwohl ich von mir behaupte, ganz fit in PHP zu sein. Ich verstehe nur einen Bruchteil der Dinge, die da abgehen. Auch wenn es für den Launch der neuen Webseite keinen fixen Termin gibt, möchte ich eigentlich schnell zu Ergebnissen kommen, und kein &amp;quot;never-ending Project&amp;quot; draus machen, an dem ich mich verhebe. Schließlich ist das meine allererste Extension. &lt;br /&gt;
&lt;br /&gt;
Vielleicht wird eine v2 daraus, die dann Anspruch hat, eine allgemeine &amp;quot;Sport-Mannschaften-Turnierwesen&amp;quot;-Verwaltungs-Extension zu sein. Erstmal möchte ich aber mein Problem lösen. So clean wie möglich, aber auch so dirty wie nötig. &lt;br /&gt;
&lt;br /&gt;
Im Endeffekt will ich in meinem Tutorial zeigen, wie man Informationen mit Vater-Kind-Beziehungen ablegt, im BE editierbar macht, und in verschiedenen &amp;quot;Views&amp;quot; im Frontend anzeigt. Meine &amp;quot;Spezialsauerei&amp;quot; der Editierbarkeit eines Teils der Daten aus dem Frontend heraus darf jemand, der das hier nachvollziehen möchte, gerne gedanklich filtern. Da ist mir klar, dass es der reinen TL-Lehre etwas widerspricht. Ich werde diese Funktionalität auch als Letztes implementieren, und vielleicht sogar aus diesem &amp;quot;Bericht&amp;quot; her ganz rauslassen. Dann wird es nur eine Art &amp;quot;extended version&amp;quot; des [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorials], was schon fast in meine Richtung geht, was mir nur '''zu'''_ Hoppla-Hopp durch alle Schritte durchgeht. &lt;br /&gt;
&lt;br /&gt;
* Ich muss bedenken, dass alle Anwender (Der Sportwart im Backend, aber vor Allem die Turnierpaare) nun jahrelang einen gewissen Workflow bezüglich Meldeliste und Eintragen der Turnierergebnisse gewöhnt sind. Ein großer Teil unserer Turnierpaare befindet sich im mittleren bis hohen Seniorenalter, und schafft es trotzdem seine Turnierergebnisse online einzutragen. Ich kann hier keine großen Revolutionen veranstalten und möchte den technischen Ablauf deshalb möglichst nachbilden. &lt;br /&gt;
&lt;br /&gt;
Da es bisher möglich war, durch Angabe eines Paar-Passworts seine Turnierergebnisse in einem Formular einzutragen, würde ich das gerne beibehalten. Ein formelles &amp;quot;Einloggen&amp;quot; in die Seite wäre für manche Anwender wahrscheinlich schon zuviel der Veränderung :-). Außerdem schürt so etwas bei Nicht-Turnierpaaren das Gefühl, dass es für eingeloggte Personen &amp;quot;Geheimseiten&amp;quot; gibt, die ihnen nicht zur Verfügung stehen. In diesem Fall wäre das ja auch so, wäre aber nicht transparent.&lt;br /&gt;
 &lt;br /&gt;
Wenn jeder Benutzer die Formularseite &amp;quot;Turnierergebnis für Paar XY eintragen, aber nur wenn man das Paarpasswort kennt&amp;quot; sieht, wird das viel weniger Fragen aufwerfen, als wenn es auf einmal &amp;quot;Login-Möglichkeiten&amp;quot; im FE geben wird, die es bisher nicht gab. Das hat immer den Geruch von Privilegisierung, die bei den &amp;quot;Nicht-Privilegierten&amp;quot; auf Ablehnung stößt. &lt;br /&gt;
&lt;br /&gt;
Ich weiß, das klingt übertrieben, ist aber ein Erfahrungswert. Mache ich ein Frontend-Login auf die Seite, wird es sofort 10-20 Anfragen geben, ob man (als nicht-Turnierpaar) nicht auch einen Login bekommen könnte, weil man sonst ja bestimmt was verpasst...Ich will da keine Begehrlichkeiten wecken.&lt;br /&gt;
&lt;br /&gt;
* Das Problem der Datenmigration habe ich schon mal angesprochen. Sowohl in der Turnierpaarliste als auch in der Meldeliste gibt es Einträge bis in die 90er Jahre zurück, die ich natürlich ins neue System übernehmen muss.&lt;br /&gt;
 &lt;br /&gt;
Jede Normalisierung über die Beziehung &amp;quot;Turnierpaar&amp;lt;- 1:N -&amp;gt;Meldung&amp;quot; hinaus, so sinnvoll sie akademisch auch sein mag, macht mir sehr viel Arbeit beim Schreiben eines Migrationsskriptes, weil ich da nämlich dann Normalisierung algorithmisch durchführen muss, die in den alten Daten nicht vorhanden ist. Von daher würde ich gerne auch unter Missachtung von &amp;quot;clean-Design&amp;quot;-Grundsätzen bei der Konzeption der Struktur der Datenbanktabellen möglichst nah an der etablierten Form bleiben. &lt;br /&gt;
&lt;br /&gt;
Die Nachteile erscheinen mir erträglich, die Vorteile beim Arbeitsaufwand immens. Ich habe auch schon gesehen, wie mit sklavischer Normalisierungswut sich selbst in den Fuß schießt, weil man vor lauter Tabellen, die N:M-Beziehungen abbilden, kein vernünftiges SELECT mehr schreiben kann...&lt;br /&gt;
&lt;br /&gt;
Man darf da gerne anderer Meinung sein, für mein Beispiel würde ich gerne bei zwei Tabellen, eine für Turnierpaare, eine für Meldungen, bleiben. Für die Turnierpaare schaue ich mir nochmal die tl_member-Tabelle an, ob ich die Personen dort nicht  ablege, aber aus den o.g. psychologischen Gründen würde ich ungerne ein Frontend-Login einführen (müssen).&lt;br /&gt;
&lt;br /&gt;
* Auf PHP-Seite möchte ich natürlich so weit wie möglich (und so weit es meine bisherigen Kenntnisse des Frameworks es zulassen) auf das TL-Framework setzen. Ist doch klar!&lt;br /&gt;
&lt;br /&gt;
'''user: FloB'''&lt;br /&gt;
 Zitat von dl1ely&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
Handling der &amp;quot;Personen&amp;quot; als Front-Member: Werde ich mir nochmal anschauen, aber ein großes Erbe in  &lt;br /&gt;
meinem konkreten Fall ist leider die Notwendigkeit, schon bestehende Daten zu migrieren, insbesondere die  &lt;br /&gt;
Liste der Turnierpaare, die bis in die 90er Jahre zurückreicht. [...] &lt;br /&gt;
Die &amp;quot;Alten&amp;quot; nutzen die Seite eh nicht mehr, sollen sowieso nicht mehr ihre alten Einträge editieren dürfen, und  &lt;br /&gt;
sind (ehrlich gesagt) inzwischen teilweise verstorben. Für einen Großteil der Personen, die (inaktive) Paare  &lt;br /&gt;
bilden, müsste ich aus dem alten &amp;quot;Paar&amp;quot;-Datensatz zwei Datensätze für die tl_member-Tabelle erstellen, und  &lt;br /&gt;
mir dabei größtenteils die Inhalte der Datenfelder (email, passwort, whatever) ausdenken.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nun, aus was bestehen denn die bestehenden Daten? Name, Geburtsdatum ist klar, dann noch Tanzpartner (am besten UserID - oder &amp;quot;Gruppen-ID&amp;quot;, sprich zwei Partner bekommen eine neue Nummer? Damit wäre auch der Grundstein gelegt, ganze Tanzgruppen ohne Mehraufwand anzulegen), Turnierklasse, aktive Jahre. Diese Felder kann man ja problemlos zu tl_member hinzufügen.&lt;br /&gt;
&lt;br /&gt;
Wenn du diese Daten in einem bestimmten Format hast (CSV, XML o. ä.) kannst du sie per SQL importieren. Die Daten, die du von manchen Personen nicht hast (E-Mail etc.) musst du da nicht angeben - nur wenn man versucht diese Einträge über das Backend / Frontend zu ändern, meckert TL. Frontendanzeige sollte problemlos funktionieren. Somit hast du die saubere Integration von Nutzer und Paaren.&lt;br /&gt;
&lt;br /&gt;
OK, ich verstehe dein Argument, dass das möglicherweise ein wenig Overkill für diese Art von Daten ist. Dann wäre es sinnvoll für Paare eine zugehörige &amp;quot;Verwalter-ID&amp;quot; zu geben, die auf einen Member-Account verweist. Dieser Member kann dann alle Einträge ändern, auf dessen die Paare / Personen verweisen. Ein zusätzliches Feld für die Trainer-ID (hinter dem auch ein Member steckt) in der Paarliste ermöglicht dann dem Trainer zusätzliche Einstellungen an der Paarung vorzunehmen (z. B. Turnier bestätigen).&lt;br /&gt;
&lt;br /&gt;
'''user: dl1ely'''&lt;br /&gt;
&lt;br /&gt;
Hehe, ihr blast das Ding schon viel zu weit auf...Trainer-ID o.ä. ist nicht notwendig, Trainer spielen in diesem &amp;quot;Prozess&amp;quot; keine Rolle. Ich denke es wird klarer (vielleicht auch enttäuschender), wenn ich die SQL-Files für meine Daten zeige. Es ist eigentlich recht billig, gerade für einen &amp;quot;TL-Profi&amp;quot;. Aber das bin ich noch nicht ;-).&lt;br /&gt;
&lt;br /&gt;
Die Daten liegen noch in einer (anderen) MySQL-Datenbank. Der technische Vorgang der Migration ist kein Problem, aber ich werde per Skript manche Felder der bisherigen Datenbankstruktur verändern müssen, um es meiner geplanten neuen Struktur anzupassen.&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-00_Vorbemerkung</id>
		<title>TEE-00 Vorbemerkung</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-00_Vorbemerkung"/>
				<updated>2010-07-07T09:47:32Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
Tagebuch einer Extension-Entwicklung / Vorbemerkungen der Wiki-Autoren&lt;br /&gt;
[[Category:Tagebuch_einer_Extension-Entwicklung]]&lt;br /&gt;
{{AppliesTo&lt;br /&gt;
|Ext1=Extension Creator&lt;br /&gt;
|TLVersion=ab TL 2.8}}&lt;br /&gt;
&lt;br /&gt;
=Vorbemerkungen=&lt;br /&gt;
* Die Artikel nehmen einen sehr ausführlichen Forumsthread aus dem Contao-Community-Forum ''Allgemeine Infos für Third-Party Extensions -&amp;gt; Entwickler-Tutorials'' auf, der unter dem Titel ''Tagebuch einer Extension-Entwicklung'' von dl1ely (Stefan) verfasst wurde. &lt;br /&gt;
&lt;br /&gt;
* Sie finden den Thread hier: [[http://www.contao-community.de/showthread.php?6570-Tagebuch-einer-Extension-Entwicklung Original Forumsbeitrag]]. Dort können Sie die Diskussion weiterführen. Ob künftige Forumsbeiträge hier eingearbeitet werden, ist nicht sichergestellt.&lt;br /&gt;
&lt;br /&gt;
* Die Originalbeiträge wurden redaktionell leicht überarbeitet. Dabei wurden neben forumsspezifischen Besonderheiten auch Überleitungen, Anrede- und Grußformeln, Bewertungen (&amp;quot;Ich finde das Tutorial gaaaanz toll!&amp;quot;) u.ä. entfernt.&lt;br /&gt;
&lt;br /&gt;
* An einigen Stellen wurden kleine Ergänzungen eingefügt.&lt;br /&gt;
&lt;br /&gt;
* Entgegen den Wiki-Gepflogenheiten sind die Artikel in der Ich-Form gehalten, da es sich um einen Erfahrungsbericht handelt.&lt;br /&gt;
&lt;br /&gt;
* Im Großen und Ganzen orientiert sich das Tutorial an der TL/contao-Systematik und besteht daher aus den zwei Blöcken ''Backend'' und ''Frontend''. Eine strikte thematische Gliederung ist hier allerdings nicht möglich. Als Erfahrungsbericht glänzt das Tutorial ja gerade dadurch, dass die im Verlauf der Entwicklung auftretenden Probleme und Fragestellungen abgearbeitet werden und entsprechende Rücksprünge an vorherige, bereits erledigt geglaubte Bearbeitungsschritte erfordern. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Und so ist das Tutorial aufgebaut:&lt;br /&gt;
&lt;br /&gt;
*TEE-00 Vorbemerkungen&lt;br /&gt;
&lt;br /&gt;
*TEE-01 Einleitung&lt;br /&gt;
*TEE-02 Extension Creator&lt;br /&gt;
*TEE-03 Backend BE-Modul und SQL&lt;br /&gt;
*TEE-04 Backend DCA&lt;br /&gt;
*TEE-05 Backend Language Files&lt;br /&gt;
*TEE-06 Backend Callbacks und Subpaletten&lt;br /&gt;
*TEE-07 Frontend 01&lt;br /&gt;
*TEE-08 Frontend 02&lt;br /&gt;
*TEE-09 Frontend 03&lt;br /&gt;
*TEE-10 Frontend 04&lt;br /&gt;
*TEE-11 Frontend 05&lt;br /&gt;
*TEE-12 Frontend 06&lt;br /&gt;
*TEE-13 Frontend 07&lt;br /&gt;
*TEE-14 Downloads&lt;br /&gt;
*TEE-15 Werkzeuge&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/TEE-00_Vorbemerkung</id>
		<title>TEE-00 Vorbemerkung</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/TEE-00_Vorbemerkung"/>
				<updated>2010-07-07T09:41:33Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: hat „Tagebuch einer Extension-Entwicklung“ nach „TEE-00 Vorbemerkung“ verschoben:&amp;amp;#32;Das Thema wurde wegen des grossen Umfangs auf mehrere Seiten aufgeteilt und in eine eigene (Unter-)Kategorie überführt.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{stub}}&lt;br /&gt;
[[Category:Dev_HOWTOS]]&lt;br /&gt;
{{AppliesTo|Ext1=Extension Creator|TLVersion=ab TL 2.8}}&lt;br /&gt;
=Vorbemerkung=&lt;br /&gt;
Dieser Artikel nimmt einen sehr ausführlichen Forumsbeitrag aus dem Contao-Community-Forum ''Allgemeine Infos für Third-Party Extensions -&amp;gt; Entwickler-Tutorials'' auf, der unter dem Titel ''Tagebuch einer Extension-Entwicklung'' von dl1ely (Stefan) verfasst wurde. Sie finden den Beitrag hier: [[http://www.contao-community.de/showthread.php?6570-Tagebuch-einer-Extension-Entwicklung Original Forumsbeitrag]]&lt;br /&gt;
&lt;br /&gt;
Entgegen den Wiki-Gepflogenheiten ist dieser Artikel in der Ich-Form gehalten, da es sich um einen Erfahrungsbericht handelt.&lt;br /&gt;
=Allgemeine Hinweise=&lt;br /&gt;
Ich möchte hier gerne eine Art &amp;quot;Tagebuch&amp;quot; einer Extension-Entwicklung schreiben. Ich besitze das TL-Buch, ich kenne das &amp;quot;Hello, World&amp;quot;-Beispiel, ich kenne das [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorial], ich kenne das FlowPlayer-Beispiel.&lt;br /&gt;
 &lt;br /&gt;
Trotzdem ist mir weiterhin nicht glasklar, welche Schritte man bis zur eigenen Extension gehen muss. Ich bin PHP-erfahren, habe aber noch nie eine TL-Extension geschrieben. Ich möchte mit diesem Tagebuch anderen &amp;quot;Anfängern&amp;quot; die Möglichkeit geben, an einem realen Beispiel zu lernen, und auch meine Entscheidungen und Gedanken entlang des Wegs kennen zulernen. In vielen Tutorials wird nur vorgegeben, was in welche Datei geschrieben wird, und was Zeile X oder Zeile Y dort tut. Der Prozess hin zu Zeile X oder Y bleibt leider zu oft im Dunkeln, und erschwert mir die Übertragung der vorgestellten Tutorial-Inhalte auf meine eigenen Probleme. Ich möchte hier auch Irrwege dokumentieren, wie sie für Extension-Anfänger wahrscheinlich typisch sind, und nicht nur ein Tutorial zum Endprodukt abliefern. Ich hoffe, die Foren-Admin akzeptieren so etwas als &amp;quot;Tutorial&amp;quot;, falls nicht, dann bitte ich um Verschiebung in die &amp;quot;Fragen&amp;quot;-Sektion. Wobei ich eher berichten als fragen möchte. Natürlich freue ich mich auch über Hinweise, wenn ich vielleicht ganz in die falsche Richtung denke, oder ich im Rahmen meines &amp;quot;Tutorials&amp;quot; selbst nicht mehr weiter weiß. &lt;br /&gt;
&lt;br /&gt;
Vorneweg:&lt;br /&gt;
TL = TYPOlight&lt;br /&gt;
FE = Frontend (Seite, die jeder Surfer sieht)&lt;br /&gt;
BE = Backend (Seite, die nur eingeloggte &amp;quot;Redakteure&amp;quot; sehen unter der /typolight URL)&lt;br /&gt;
&lt;br /&gt;
Alles soll sich unter TL 2.8.0 abspielen, und ich werde den Extension Creator verwenden, um mir das &amp;quot;Skelett&amp;quot; der Extension zu erstellen.&lt;br /&gt;
Die Extension wird sehr speziell auf die Bedürfnisse der von mir betreuten Seite zugeschnitten sein. Ich glaube nicht, dass mit dem engen Scope jemand anders sie nutzen kann. Darum werde ich sie wohl auch nicht im Extension-Repository veröffentlichen. Ich kann und werde den Quelltext aber sicherlich zur Verfügung stellen, sei es zur Benutzung oder zum &amp;quot;Studium&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=Anforderungen und Randbedingungen=&lt;br /&gt;
Zunächst mal zum Hintergrund:&lt;br /&gt;
Ich bin Webmaster der Seite http://www.gruen-weiss-aachen.de , der Webpräsenz des momentan größten Tanzsportvereins in NRW, und einem der größten in Deutschland. Wie man unschwer erkennen kann, bedarf die Seite dringend eines Relaunchs, der auf Basis von TYPOlight erfolgen soll. Dazu erfolgt auf einer Subdomain parallel zum weiteren Betrieb der bisherigen Webseite der Aufbau einer TL-basierten Seite.&lt;br /&gt;
 &lt;br /&gt;
Das Design steht noch nicht, erstmal soll die technische Funktionalität geschaffen werden. 95% der bisherigen Seiteninhalte lassen sich mit &amp;quot;TL-Bordmitteln&amp;quot; oder schon verfügbaren Extensions wie efg erschlagen. Allerdings gibt es auf der alten Seite einige &amp;quot;handgestrickte&amp;quot; PHP-Skripte, deren Funktionalität mehr oder weniger auf der neuen Seite erhalten bleiben soll.&lt;br /&gt;
&lt;br /&gt;
Eine Funktionalität, die sich mit verfügbaren Extensions meiner Meinung nach nicht nachbilden lässt, und für die ich deshalb eine eigene Extension entwickeln möchte/muss, ist folgende:&lt;br /&gt;
&lt;br /&gt;
Der Verein besitzt eine Menge an Tanzturnierpaaren. Zu diesen Turnierpaaren gehören Daten wie Name(n), Start- und Alterklassen, und ein Flag, ob es noch aktiv ist. Diese Daten werden von einer berechtigten Person (Sportwart) im BE gepflegt. Zusätzlich gehört zu einem Turnierpaar eine Art &amp;quot;Visitenkarte&amp;quot; mit Bild, Freitext, Email-Adresse, Telefonnummer...Diese Daten sollen auch im Backend pflegbar sein, zusätzlich sollen diese Daten aber auch von dem Turnierpaar selbst unter Kenntnis eines individuellen Passworts veränderbar sein. Dazu möchte ich aber KEINE Frontend-User-Verwaltung nutzen.&lt;br /&gt;
 &lt;br /&gt;
Für jedes Turnierpaar gibt es N &amp;quot;Meldungen&amp;quot;, dies sind Datensätze, die enthalten, zu welchem Tanzturnier ein Paar fahren wird/gefahren ist. Turnierpaare informieren den Sportwart darüber, bei welchen Turnieren sie starten wollen. Der Sportwart führt die Anmeldung beim Turnierveranstalter durch (So ist das Procedere im Tanzsport), und trägt danach die &amp;quot;Meldung&amp;quot; in der Datenbank ein. Auf der sog. &amp;quot;Meldeliste&amp;quot; kann das Tanzpaar dann selbst sehen, ob es zu einem Turnier gemeldet worden ist. Die Liste der Meldungen (1:N-Beziehung zu den Turnierpaaren) wird vom Sportwart im BE gepflegt. Auch hier gibt es die Möglichkeit, dass ein Turnierpaar unter Kenntnis seines Passworts seinen erzielten Platz auf einem Turnier und einen freien Kommentar zu einer Meldung hinzufügen kann.&lt;br /&gt;
 &lt;br /&gt;
Sollte das Tanzpaar das Turnier seiner Leistungsklasse gewonnen haben, darf es direkt im Anschluss das Turnier der nächsthöheren Klasse mittanzen (Ohne Meldung durch den Sportwart). Hier muss es die Möglichkeit geben, dass das Paar selbst einen Meldungs-Eintrag in der Datenbank vornehmen kann (Das sog. Folgeturnier).&lt;br /&gt;
 &lt;br /&gt;
Die Meldeliste dient also mehreren Zwecken:&lt;br /&gt;
* Rückmeldung vom Sportwart an die Paare, dass die Meldung beim Veranstalter erfolgt ist&lt;br /&gt;
* Außenwirkung für den Verein: Wie viele Paare haben wir, und wo starten sie&lt;br /&gt;
* Außenwirkung für die Tanzpaare selbst: Wie gut haben wir abgeschnitten&lt;br /&gt;
&lt;br /&gt;
Übertragen auf die Tabellenstruktur handelt es sich also um die Tabelle der Turnierpaare, klassisch im BE durch ein BE-Modul gepflegt. Die Meldungen sind &amp;quot;Childs&amp;quot; der Turnierpaare, und sollten so auch im Backend angezeigt werden (Wie Artikel - Inhaltselemente). Zugriff auf das BE-Modul hat nur der Sportwart.&lt;br /&gt;
 &lt;br /&gt;
Zusätzlich soll es einen Mechanismus geben, unter Angabe eines Tanzpaar-spezifischen Passworts bestimmte Felder in der Tanzpaar-Tabelle und in der Melde-Tabelle durch ein Frontend-Formular zu verändern. Außerdem soll es die Möglichkeit geben, einen neuen Satz in der Melde-Tabelle anzulegen.&lt;br /&gt;
 &lt;br /&gt;
Die Ausgabe der Daten im Frontend soll auf verschiedene Weisen geschehen:&lt;br /&gt;
&lt;br /&gt;
* Modul ''Aktive Turnierpaare''&lt;br /&gt;
&lt;br /&gt;
* Modul ''Ehemalige Turnierpaare''&lt;br /&gt;
&lt;br /&gt;
Für beide Module jeweils eine Detail-Ansicht des gewählten Turnierpaares mit Bild, Freitext, freigegebenen Kontaktdaten wie Telefon oder Email, und einer Liste aller Meldungen dieses Paares.&lt;br /&gt;
&lt;br /&gt;
* Modul ''Meldeliste'' - Eine chronologisch absteigend sortierte Liste aller Melde-Einträge, Neueste also zuerst.&lt;br /&gt;
&lt;br /&gt;
* Module/Formulare für Änderung der Paardaten im Frontend und zum Hinzufügen von Platzierung/Kommentar bei Meldungen&lt;br /&gt;
&lt;br /&gt;
Da das Ergänzen/Ändern der einzelnen Tabellenfelder mithilfe des Paar-Passworts ohne die Einführung von Frontend-Usern doch ziemlich an der TL-Philosophie vorbeigeht, tendiere ich momentan dazu, dafür Formulare zu verwenden, deren Weiterleitungsziel eine Seite ist, die per insert-Tag ein stand-alone-PHP-File einbindet, was nach Prüfung des Passworts die entsprechenden Datenbankfelder updatet.&lt;br /&gt;
&lt;br /&gt;
Gibt es hier eigentlich Erfahrungen mit zeitgleichem Zugriff auf Tabellen bei zwei eingeloggten BE-Usern, oder wie hier in meinem Fall, wenn ein Skript auf FE-Seite potentiell Daten in der Datenbank ändert, die vielleicht gerade ein BE-User betrachtet? Aber damit werde ich leben, die Kollisionswahrscheinlichkeit ist sehr gering.&lt;br /&gt;
&lt;br /&gt;
Coming up next: Extension-&amp;quot;Skelett&amp;quot; anlegen mit dem Extension-Creator.&lt;br /&gt;
&lt;br /&gt;
==Diskussionsbeiträge aus dem Forum==&lt;br /&gt;
{{Hinweis| Diskussionsbeiträge aus dem Forum einarbeiten!}}&lt;br /&gt;
=Extension Creator=&lt;br /&gt;
Also, los geht es mit dem Skelett für die geplante Extension. Ich verwende den Extension-Creator aus dem Extension-Repository.&lt;br /&gt;
&lt;br /&gt;
* Titel: Es geht um Turnierpaar-&amp;quot;Verwaltung&amp;quot;, und um Namenskonflikte zu vermeiden möchte ich gerne einen spezifischen Präfix nutzen: gw angelehnt an den Vereinsnamen &amp;quot;Grün-Weiß&amp;quot;. Also: Titel = ''gw_turnierpaare''. An dieser Stelle bin ich mir noch nicht so sicher, wo dieser &amp;quot;Titel&amp;quot; überall erscheinen wird, und ob es deshalb ein beliebiger Text sein soll, oder eher ein &amp;quot;identifier&amp;quot;, also z.b. ohne Leerzeichen u.ä. Sicherheitshalber gehe ich den Identifier-Weg. Besser hässlich als nicht-funktionierend.&lt;br /&gt;
&lt;br /&gt;
* Ordnername: Ebenfalls ''gw_turnierpaare''.&lt;br /&gt;
&lt;br /&gt;
* Autor, Copyright und Lizenz: Selbsterklärend&lt;br /&gt;
&lt;br /&gt;
* Paket: Ein Paketname ist gefragt. Der Hilfetext unter dem Eingabefeld schlägt hilfreich &amp;quot;z.B. meinEigenesModul&amp;quot; vor. Ist das Modul jetzt das Paket? Was ist ein Paket? Sowas wie ein Namensraum? Da ich noch nicht weiß, ob ich für die Vereinsseite noch andere Extensions pogrammieren werde, nehme ich die Vereinsabkürzung als &amp;quot;Paketname&amp;quot;, also ''GW''. Weitere vereinsspezifische Extensions würde ich dann in dasselbe Paket stecken.&lt;br /&gt;
&lt;br /&gt;
* Ein Backend-Modul hinzufügen: Ja klar, schließlich sollen Daten im Backend bearbeitet werden. Also dort ein Häkchen.&lt;br /&gt;
&lt;br /&gt;
* Backend-Klassen: Wenig hilfreicher Erklärungstext: &amp;quot;Hier können Sie eine kommagetrennte Liste der zu erstellenden Backend-Klassen eingeben.&amp;quot; - Was sind Backend-Klassen? Wofür brauche ich die? Eigentlich müsste doch alles, was ich im Backend vorhabe, durch Einträge im DCA-File realisierbar sein, schließlich geht es nur um Pflege von zwei abhängigen Datenbanktabellen. Also mal mutig leer gelassen, falls das falsch ist kann man es später noch hinzufügen.&lt;br /&gt;
&lt;br /&gt;
* Backend-Tabellen: Das sind wohl meine Datentabellen, ich will eine für Turnierpaare, eine für Meldungen, also: ''tl_gw_turnierpaare,tl_gw_meldungen''.&lt;br /&gt;
&lt;br /&gt;
* Backend-Templates: Auch hier wieder wenig erhellender Hilfetext. Auch das TL-Buch beschränkt sich da leider fast auf das Abschreiben der Hilfetexte unter den Eingabefeldern. Ich kenne Templates nur für das Frontend, also beschließe ich mutig, dass ich das wohl nicht brauche. Sollte sich das später als Irrtum herausstellen, wird es sich hoffentlich noch korrigieren lassen.&lt;br /&gt;
&lt;br /&gt;
* Ein Frontend-Modul hinzufügen: Aber klar, die Daten sollen schließlich im Frontend visualisiert werden. Also Haken dran.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Klassen: So weit wie ich es bisher verstanden habe, braucht jedes Modul eine eigene Klasse. Nach meiner bisherigen Planung brauche ich ein Modul ''Turnierpaarliste'' inklusive Detail-Ansicht der einzelnen Paar-Einträge. Die Unterscheidung aktiv/nicht aktiv würde ich gerne über einen Parameter im Modul lösen, so dass dasselbe Modul die Liste der aktiven und der ehemaligen Paare anzeigen kann. Außerdem benötige ich ein Modul ''Meldeliste'' mit der chronologisch sortierten Übersicht der Meldungen. Also: ''gwTurnierpaarliste,gwMeldeliste'' als Klassennnamen.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Tabellen: Ratlosigkeit. Was unterscheidet Frontend-Tabellen von Backend-Tabellen? Da ich meine Tabellen schon in den Backend-Tabellen abgehandelt habe, lasse ich das Feld leer.&lt;br /&gt;
&lt;br /&gt;
* Frontend-Templates: Natürlich! ''gw_turnierpaarliste,gw_turnierpaarliste_detail,gw _meldeliste'' fallen mir sofort ein, vielleicht genügt das schon. Falls nicht, kann ich später noch welche hinzufügen.&lt;br /&gt;
&lt;br /&gt;
* Sprachpakete erstellen: Natürlich. Auch wenn es wahrscheinlich niemand in Englisch benutzen wird, tut es mir aber auch nicht weh, also Sprachen = ''en,de''.&lt;br /&gt;
&lt;br /&gt;
Dann &amp;quot;speichern und schließen&amp;quot;, und auf den grünen Haken am Ende der neuen Zeile ''gw_turnierpaare'' im Extension-Creator geklickt. Die Warnung bestätigt, und der Extension-Creator hat mir erstmal den Grundstock an Files in ''/system/modules/gw_turnierpaare/'' erzeugt.&lt;br /&gt;
 &lt;br /&gt;
Und zwar:&lt;br /&gt;
&lt;br /&gt;
* ''gwMeldeliste.php,gwTurnierpaarliste.php'': meine Frontendklassen&lt;br /&gt;
&lt;br /&gt;
* ''config/config.php'' und ''config/database.sql'' (Letzteres für meine SQL-Tabellenstruktur)&lt;br /&gt;
&lt;br /&gt;
* ''dca/tl_gw_turnierpaare.php'' und ''dca/tl_gw_meldungen.php'': Die DCA-Definitionen für meine Tabellen zur Bearbeitung im Backend&lt;br /&gt;
&lt;br /&gt;
* ''languages/...'': Die Sprachfiles in en und de-Variante&lt;br /&gt;
&lt;br /&gt;
* ''templates/...'': Die drei Frontend-Templates, die ich angegeben hatte&lt;br /&gt;
&lt;br /&gt;
Im nächsten Schritt orientieren wir uns etwas und beginnen, die vorgegebenen Files zu modifizieren.&lt;br /&gt;
&lt;br /&gt;
P.S.: Wenn die erfahrenen TL-Programmierer jetzt schon Gänsehaut haben: Sorry. Ich mache das zum ersten &lt;br /&gt;
Mal, und stelle mich nicht künstlich dumm an. Ich versuche so zu schildern, wie ich als Einsteiger die Sachen &lt;br /&gt;
sehe, was mich verwirrt usw...Bin für Verbesserungsvorschläge z.B. zu Namens-Schemata usw immer zu haben. &lt;br /&gt;
Genauso freue ich mich über Aufklärung zu Dingen, die ich selbst nicht verstehe...Backendklassen, Backend-&lt;br /&gt;
Templates, Frontend-Tabellen, Paket... &lt;br /&gt;
&lt;br /&gt;
=Backend-Modul registrieren=&lt;br /&gt;
Jetzt geht es also an die Files, die uns der Extension-Generator im letzten Schritt erzeugt hat. Ich verwende WinSCP unter Windows 7 und PSPad als Editor.&lt;br /&gt;
&lt;br /&gt;
Zunächst will ich mein Backend-Modul in TYPOlight bekannt machen. Dafür öffne ich ''/system/modules/gw_turnierpaare/config/config.php''.&lt;br /&gt;
&lt;br /&gt;
Im Skelett dieser Datei sind schon Abschnitte für die Eintragung von Backend-Modulen, Front-Modulen, Content Elementen, Hooks und noch viel mehr vorgesehen. Ich orientiere mich am [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorial] und trage im Abschnitt für Backend-Module folgendes ein:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$GLOBALS['BE_MOD']['content']['gw_turnierpaare'] = array &lt;br /&gt;
( &lt;br /&gt;
    'tables' =&amp;gt; array('tl_gw_turnierpaare','tl_gw_meldungen'), &lt;br /&gt;
    'icon'   =&amp;gt; 'system/modules/gw_turnierpaare/icons/turnierpaare.png' &lt;br /&gt;
);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hiermit registriere ich ein Modul mit dem Bezeichner ''gw_turnierpaare'', das sich auf die Datenbanktabellen ''tl_gw_turnierpaare'' und ''tl_gw_meldungen'' stützt (wie im Extension-Generator angegeben). In der Liste der Backend-Module (linke Spalte im Backend) soll ein Icon vor dem Bezeichner angezeigt werden, dessen Pfad ich unter 'icon' angegeben habe. Das Icon, was ich mir ausgesucht habe, ist an diesen Post angehängt. Ich habe mich für ein eigenes Unterverzeichnis für mögliche weitere Icons entschieden, und deshalb manuell das Unterverzeichnis &amp;quot;icons&amp;quot; angelegt und mein Icon dort hochgeladen. Im Backend-Modul soll der Berechtigte (also &lt;br /&gt;
der Sportwart) die Daten Anlegen/Löschen/Ändern dürfen.&lt;br /&gt;
&lt;br /&gt;
Ich speichere die Datei zunächst, und lade meine Backend-Ansicht (als Administrator!) neu. Nun sehe ich in der linken Spalte unter &amp;quot;Inhalte&amp;quot; den neuen Eintrag ''gw_turnierpaare'' mit meinem Icon. Ein Klick darauf führt leider noch zu einer Fehlermeldung, da die SQL-Tabellen ''tl_gw_turnierpaare'' und ''tl_gw_meldungen'' noch nicht angelegt sind.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_001.png]]&lt;br /&gt;
==SQL-Tabellenstruktur anlegen==&lt;br /&gt;
Also, die Tabellen anlegen: Ich öffne ''/system/modules/gw_turnierpaare/config/database.sql'' , in der mir der Extension-Generator schon ein Skelett für meine beiden Tabellen vorgegeben hat. In beiden Tabellen sind ''id'', ''pid'', ''sorting'' und ''tstamp'' vorgegeben, sowie der primary key ''id'' und der key ''pid''. Ich vermute, dass ''pid'' die &amp;quot;Parent ID&amp;quot; ist. Meine Turnierpaare haben keinen parent, darum lösche ich die Definition von ''pid'' und die Festlegung von ''pid'' als Key.&lt;br /&gt;
&lt;br /&gt;
Ich füge meine restlichen Felder hinzu, ohne so recht zu wissen, mit welcher Syntax genau. Ich habe mal was von SQL92-Syntax gelesen, aber die kenne ich nicht. Gibt es BOOLEAN-Datentypen? Char vs. Varchar? Sicherheitshalber halte ich mich erstmal an die MySQL-Syntax. Im Endeffekt sieht der Abschnitt für ''tl_gw_turnierpaare'' in ''database.sql'' so aus:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE `tl_gw_turnierpaare` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `partnernachname` varchar(64) NOT NULL default '_',&lt;br /&gt;
  `partnervorname` varchar(64) NULL,&lt;br /&gt;
  `partnerinnachname` varchar(64) NULL,&lt;br /&gt;
  `partnerinvorname` varchar(64) NULL,&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '_',&lt;br /&gt;
  `startklasselatein` varchar(12) NULL,&lt;br /&gt;
  `startklassestandard` varchar(12) NULL,&lt;br /&gt;
  `aktiv` int(1) NOT NULL default '0',&lt;br /&gt;
  `aktivseit` int(4) NULL,&lt;br /&gt;
  `aktivbis` int(4) NULL,&lt;br /&gt;
  `password` varchar(32) NULL,&lt;br /&gt;
  `bild` varchar(255) NULL,&lt;br /&gt;
  `anschrift` text NULL,&lt;br /&gt;
  `zeigeanschrift` int(1) NOT NULL default '0',&lt;br /&gt;
  `telefon` varchar(32) NULL,&lt;br /&gt;
  `zeigetelefon` int(1) NOT NULL default '0',&lt;br /&gt;
  `fax` varchar(32) NULL,&lt;br /&gt;
  `zeigefax` int(1) NOT NULL default '0',&lt;br /&gt;
  `mobil` varchar(32) NULL,&lt;br /&gt;
  `zeigemobil` int(1) NOT NULL default '0',&lt;br /&gt;
  `email` varchar(128) NULL,&lt;br /&gt;
  `zeigeemail` int(1) NOT NULL default '0',&lt;br /&gt;
  `homepage` varchar(128) NULL,&lt;br /&gt;
  `zeigehomepage` int(1) NOT NULL default '0',&lt;br /&gt;
  `beschreibung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Man kann sich hier jetzt beliebige Gedanken über die Datenstruktur, Abstraktion, Normalisierung usw machen. Ich möchte es jetzt '''so''' lösen.&lt;br /&gt;
&lt;br /&gt;
Meine Meldungen in ''tl_gw_meldungen'' sollen parents haben (nämlich die Turnierpaare), darum lasse ich das Skelett so, und erweitere um meine eigenen Felder. Für meinen Fall kommt das hier heraus:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE `tl_gw_meldungen` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `pid` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `datum` date NOT NULL default '1900-01-01',&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '_',&lt;br /&gt;
  `startklasse` varchar(12) NOT NULL default '_',&lt;br /&gt;
  `lat_std` char(1) NOT NULL default '_',&lt;br /&gt;
  `turnierort` varchar(128) NOT NULL default '_',&lt;br /&gt;
  `turnierart` varchar(64) NULL,&lt;br /&gt;
  `anzahlpaare` int(4) NULL,&lt;br /&gt;
  `platz_von` int(4) NULL,&lt;br /&gt;
  `platz_bis` int(4) NULL,&lt;br /&gt;
  `bemerkung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
  KEY `pid` (`pid`)&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich speichere ''database.sql'' und rufe ''/typolight/install.php'' in meiner TYPOlight-Installation auf. TYPOlight bemerkt, daß die Datenbankstruktur nicht mehr aktuell ist, und schlägt mir vor, meine Tabellen anzulegen. Ich bestätige das.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_002.png]] &lt;br /&gt;
&lt;br /&gt;
Was dann kommt, erstaunt mich dann aber doch etwas: Die Datenbankstruktur soll weiterhin nicht aktuell sein:&lt;br /&gt;
&lt;br /&gt;
[[Datei:attachment_003.png]]&lt;br /&gt;
&lt;br /&gt;
Auch wenn ich diese Vorschläge bestätige, ändert sich nichts. Ein Blick in die Datenbank zeigt aber, dass die Tabellen wie von mir gewünscht angelegt wurden. Irgendwie kommt TYPOlight dort ins Schleudern. Ein Klick auf ''gw_turnierpaare'' im Backend verläuft jetzt aber ohne Fehlermeldung, auch wenn in diesem Backend-Modul noch nichts &amp;quot;passiert&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Meine Frage an dieser Stelle also an die erfahrenen Entwickler: Was ist an meiner SQL-Definition &amp;quot;falsch&amp;quot;, dass die Tabellen zwar richtig angelegt werden, das TYPOlight-Install-Tool aber damit nicht zurecht kommt?&lt;br /&gt;
===Diskussionsbeiträge aus dem Forum===&lt;br /&gt;
{{Hinweis| Diskussionsbeiträge aus dem Forum einarbeiten!}}&lt;br /&gt;
==SQL reloaded==&lt;br /&gt;
Nach kleinem Kampf mit dem Install-Tool sieht das SQL für meine beiden Tabellen in database.sql nun so aus:&lt;br /&gt;
&lt;br /&gt;
Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE `tl_gw_turnierpaare` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `partnernachname` varchar(64) NOT NULL default '',&lt;br /&gt;
  `partnervorname` varchar(64) NULL default NULL,&lt;br /&gt;
  `partnerinnachname` varchar(64) NULL default NULL,&lt;br /&gt;
  `partnerinvorname` varchar(64) NULL default NULL,&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '',&lt;br /&gt;
  `startklasselatein` varchar(12) NULL default NULL,&lt;br /&gt;
  `startklassestandard` varchar(12) NULL default NULL,&lt;br /&gt;
  `aktiv` int(1) NOT NULL default '0',&lt;br /&gt;
  `aktivseit` int(4) NULL default NULL,&lt;br /&gt;
  `aktivbis` int(4) NULL default NULL,&lt;br /&gt;
  `password` varchar(32) NULL default NULL,&lt;br /&gt;
  `bild` varchar(255) NULL default NULL,&lt;br /&gt;
  `anschrift` text NULL,&lt;br /&gt;
  `zeigeanschrift` int(1) NOT NULL default '0',&lt;br /&gt;
  `telefon` varchar(32) NULL default NULL,&lt;br /&gt;
  `zeigetelefon` int(1) NOT NULL default '0',&lt;br /&gt;
  `fax` varchar(32) NULL default NULL,&lt;br /&gt;
  `zeigefax` int(1) NOT NULL default '0',&lt;br /&gt;
  `mobil` varchar(32) NULL default NULL,&lt;br /&gt;
  `zeigemobil` int(1) NOT NULL default '0',&lt;br /&gt;
  `email` varchar(128) NULL default NULL,&lt;br /&gt;
  `zeigeemail` int(1) NOT NULL default '0',&lt;br /&gt;
  `homepage` varchar(128) NULL default NULL,&lt;br /&gt;
  `zeigehomepage` int(1) NOT NULL default '0',&lt;br /&gt;
  `beschreibung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
CREATE TABLE `tl_gw_meldungen` (&lt;br /&gt;
  `id` int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
  `pid` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `sorting` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `tstamp` int(10) unsigned NOT NULL default '0',&lt;br /&gt;
  `datum` date NOT NULL default '1900-01-01',&lt;br /&gt;
  `startgruppe` varchar(32) NOT NULL default '',&lt;br /&gt;
  `startklasse` varchar(12) NOT NULL default '',&lt;br /&gt;
  `lat_std` char(1) NOT NULL default '',&lt;br /&gt;
  `turnierort` varchar(128) NOT NULL default '',&lt;br /&gt;
  `turnierart` varchar(64) NULL default NULL,&lt;br /&gt;
  `anzahlpaare` int(4) NULL default NULL,&lt;br /&gt;
  `platz_von` int(4) NULL default NULL,&lt;br /&gt;
  `platz_bis` int(4) NULL default NULL,&lt;br /&gt;
  `bemerkung` text NULL,&lt;br /&gt;
  PRIMARY KEY  (`id`),&lt;br /&gt;
  KEY `pid` (`pid`)&lt;br /&gt;
) ENGINE=MyISAM DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
und wir merken uns:&lt;br /&gt;
&lt;br /&gt;
* NOT NULL-Felder mit default (logisch)&lt;br /&gt;
&lt;br /&gt;
* NULL-&amp;quot;text&amp;quot;-Felder OHNE default&lt;br /&gt;
&lt;br /&gt;
* Sonstige NULL-Felder mit &amp;quot;default NULL&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* default _KLEIN_ schreiben&lt;br /&gt;
&lt;br /&gt;
* Und falls man da was verändert: _2_ Leerzeichen zwischen PRIMARY KEY und (`id`)&lt;br /&gt;
&lt;br /&gt;
Und hier nochmal der Link zum Thread, der das erklärt: [http://www.typolight-community.de/showthread.php?t=41. contao-community-forum]&lt;br /&gt;
&lt;br /&gt;
So, das Install-Tool ist zufrieden, die Datenbank-Tabellen angelegt - es kann weiter gehen!&lt;br /&gt;
&lt;br /&gt;
=Wir wagen uns in das DCA-Land=&lt;br /&gt;
Jetzt kommt es zu einem (vermutlich) harten Brocken. Mein backend-Modul wird links in der Navigation des Backends angezeigt, aber man kann noch keine Datensätze anlegen oder verändern. Dafür müssen wir einen passenden &amp;quot;DCA-Record&amp;quot; anlegen. Ich werde mich wieder vom [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorial] und der Referenz zu den [http://www.typolight.org/dca.html DCA-Records] leiten lassen. Die Referenz ist schon mal erschlagend-beeindruckend.&lt;br /&gt;
&lt;br /&gt;
Mithilfe der DCA-Records erstellt TYPOlight die Masken, mit denen man im Backend die Tabellen füllen, verändern und löschen kann. In ''/system/modules/gw_turnierpaare/dca/tl_gw_turnierpaare.php'' hat der Extension-Generator freundlicherweise schon ein Skelett für einen DCA-Record für die Tabelle ''tl_gw_turnierpaare'' angelegt.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$GLOBALS['TL_DCA']['tl_gw_turnierpaare'] = array &lt;br /&gt;
( &lt;br /&gt;
    // Config &lt;br /&gt;
    'config' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'dataContainer'               =&amp;gt; 'Table', &lt;br /&gt;
        'enableVersioning'            =&amp;gt; true &lt;br /&gt;
    ), &lt;br /&gt;
...  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der zweite Array-Key in $GLOBALS ist der Name unserer Tabelle. Im darauffolgenden mehrfach verschachtelten Array gibt es zunächst die ''config''-Sektion. Hier wird zunächst festgehalten, dass es sich bei der Datenquelle um eine Tabelle handelt. Laut Referenz sind auch noch File und Folder vorgesehen. Sicherlich sind Tabellen der am häufigsten gebrauchte Datacontainer. ''enableVersioning'' erlaubt die Versionierung der Einträge - das ist OK und passt mir ins Konzept. Die Referenz verrät mir, daß ich eine &amp;quot;child Table&amp;quot; angeben kann. Da die Turniermeldungen Childs der Turnierpaare werden soll, ergänze ich also&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'ctable'                      =&amp;gt; 'tl_gw_meldungen'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die verbleibenden Optionen in ''config'' erscheinen mir nicht weiter von Bedeutung. Weiter geht es mit dem Abschnitt ''list'', und dort mit ''sorting'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // List &lt;br /&gt;
    'list' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'sorting' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'mode'                    =&amp;gt; 1, &lt;br /&gt;
            'fields'                  =&amp;gt; array(''), &lt;br /&gt;
            'flag'                    =&amp;gt; 1 &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sortierart und Sortierreihenfolge sind für mich erstmal ok, da ich gerne nach Nachnamen von Herrn und Dame sortieren würde, verändere ich die Zeile mit ''fields'' auf:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname','partnerinnachname'),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als nächstes kommt ein Block ''label'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'label' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'fields'                  =&amp;gt; array(''), &lt;br /&gt;
            'format'                  =&amp;gt; '%s' &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier scheint es wohl darum zu gehen, was in der Liste der schon bestehenden Tabelleneinträge eingezeigt wird. Ich verändere die Zeilen auf&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname','partnervorname','partnerinnachname','partnerinvorname','startgruppe','startklassestd','startklasselat'), &lt;br /&gt;
            'format'                  =&amp;gt; '%s, %s und %s, %s - %s %s LAT / %s STD'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Etwas &amp;quot;domain-specific knowledge&amp;quot;: Startgruppe ist im Prinzip die Altersklasse, Startklasse ist die Leistungsklasse (Die &amp;quot;Liga&amp;quot;), in der das Paar tanzt, und zwar unterschieden nach lateinamerikanischen und Standardtänzen. Diese Infos sind für den Sportwart interessant und sollten in der Übersichtsliste vorhanden sein. Die &amp;quot;''%s''&amp;quot; im format-String werden in der Reihenfolge mit Feldinhalten befüllt, wie wir sie obendrüber im Array angegeben haben. Der Aufbau des format-Strings sollte PHP- (oder C-)Programmierern bekannt sein. Dann kommt ein Abschnitt ''global_operations'' und ''operations'', den ich aber gar nicht verändern will:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'global_operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'all' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['MSC']['all'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=select', &lt;br /&gt;
                'class'               =&amp;gt; 'header_edit_all', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ) &lt;br /&gt;
        ), &lt;br /&gt;
        'operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'edit' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['edit'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=edit', &lt;br /&gt;
                'icon'                =&amp;gt; 'edit.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'copy' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['copy'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=copy', &lt;br /&gt;
                'icon'                =&amp;gt; 'copy.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'delete' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['delete'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=delete', &lt;br /&gt;
                'icon'                =&amp;gt; 'delete.gif', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;if (!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\')) return false;Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ), &lt;br /&gt;
            'show' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['show'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=show', &lt;br /&gt;
                'icon'                =&amp;gt; 'show.gif' &lt;br /&gt;
            ) &lt;br /&gt;
        ) &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Laut Referenz sollte ''global_operations'' ein Unterpunkt von ''operations'' sein, im Skelett-File des Extension-Generators stehen sie aber auf gleicher Ebene. Bin etwas verwundert, aber wird schon funktionieren. Nächster Abschnitt im vorgegeben File sind ''palettes'' und ''subpalettes''. Leider stehen die nicht in der Referenz, und auch die Seite über ''palettes'' macht mich nicht so richtig schlauer.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '' &lt;br /&gt;
    ), &lt;br /&gt;
    // Subpalettes &lt;br /&gt;
    'subpalettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        ''                            =&amp;gt; '' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ein Blick ins [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorial] verrät, dass man unter ''default'' die Felder angeben kann, die in Paletten sortiert werden sollen: Felder innerhalb der Palette mit Komma getrennt, Beginn einer neuen Palette durch ein Semikolon.&lt;br /&gt;
Da ich es zeitlich für diesen Post nicht schaffen werde, alle Felder meiner ''tl_gw_turnierpaare''-Tabelle zu definieren, will ich zunächst nur die Namensfelder definieren, und zum Testen 2 Paletten benutzen. Ich editiere den ''palettes''-Eintrag also in&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; 'partnernachname,partnervorname;partnerinnachname,partnerinvorname' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Subpalettes'' lässt mich weiterhin ratlos, also Finger weg davon. Der letzte Teil der Skelett-Datei (und hier wird es richtig spannend!) ist das ''fields''-Array:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare'][''], &lt;br /&gt;
            'exclude'                 =&amp;gt; true, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'maxlength'=&amp;gt;255&lt;br /&gt;
) &lt;br /&gt;
        ) &lt;br /&gt;
    ) &lt;br /&gt;
);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich halte mich erstmal an das Skelett, und füge nur die Feldnamen hinzu, und vervielfältige den Block auf insgesamt 4 Stück:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'partnernachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'maxlength'=&amp;gt;64) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnervorname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnervorname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnerinnachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinnachname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnerinvorname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinvorname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ) &lt;br /&gt;
    )  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Labels müssen wir später noch in den Sprachfiles definieren, ''exclude'' = ''true'' bedeutet, dass nur Admins das Feld sehen können. Da später ein Nicht-Admin die Tebelle pflegen können soll, setze ich es also überall auf ''false''. Ich hoffe mein Gedankengang ist da richtig. Wir setzen für jedes Feld die Maximallänge auf 64 Zeichen, und nur der Partner-Nachname ist verpflichtend. Warum nicht auch Vorname und der Namen der Partnerin? Ich brauche für meine Anwendung EINE klitzekleine Ausnahme, in der ich gerne eine Mannschaft in die Startliste eintragen würde. Deren Name würde dann in ''partnernachname'' stehen, die restlichen Felder wären leer.&lt;br /&gt;
&lt;br /&gt;
Für den nächsten Post wird das alles noch verfeinert, weitere Optionen für die Felder hinzugefügt und vor allem alle Felder der Tabelle im DCA-Record definiert. Aber erstmal ein kleines, bescheidenes Zwischenergebnis zur Motivation:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_004.png]]&lt;br /&gt;
&lt;br /&gt;
Und man kann auch schon was eingeben:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_005.png]]&lt;br /&gt;
&lt;br /&gt;
Da Startgruppe und Klasse(n) noch nicht einzugeben sind, bleiben die in der Übersichtsliste noch leer. Aber: Grundlegend funktioniert das schonmal, und auch den Begriff ''palette'' habe ich jetzt (anhand des Screenshots) verstanden.&lt;br /&gt;
&lt;br /&gt;
Im nächsten Post wird das alles erweitert und &amp;quot;poliert&amp;quot;. Zur Übersicht nochmal mein aktueller Stand der Datei ''/system/modules/gw_turnierpaare/dca/tl_gw_turnierpaare.php'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** &lt;br /&gt;
 * Table tl_gw_turnierpaare  &lt;br /&gt;
 */ &lt;br /&gt;
$GLOBALS['TL_DCA']['tl_gw_turnierpaare'] = array &lt;br /&gt;
( &lt;br /&gt;
    // Config &lt;br /&gt;
    'config' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'dataContainer'               =&amp;gt; 'Table', &lt;br /&gt;
        'enableVersioning'            =&amp;gt; true, &lt;br /&gt;
        'ctable'                      =&amp;gt; 'tl_gw_meldungen' &lt;br /&gt;
    ), &lt;br /&gt;
    // List &lt;br /&gt;
    'list' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'sorting' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'mode'                    =&amp;gt; 1, &lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname','partnerinnachname'), &lt;br /&gt;
            'flag'                    =&amp;gt; 1 &lt;br /&gt;
        ), &lt;br /&gt;
        'label' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname','partnervorname','partnerinnachname','partnerinvorname','startgruppe','startklassestd','startklasselat'), &lt;br /&gt;
            'format'                  =&amp;gt; '%s, %s und %s, %s - %s %s LAT / %s STD' &lt;br /&gt;
        ), &lt;br /&gt;
        'global_operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'all' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['MSC']['all'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=select', &lt;br /&gt;
                'class'               =&amp;gt; 'header_edit_all', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ) &lt;br /&gt;
        ), &lt;br /&gt;
        'operations' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'edit' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['edit'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=edit', &lt;br /&gt;
                'icon'                =&amp;gt; 'edit.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'copy' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['copy'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=copy', &lt;br /&gt;
                'icon'                =&amp;gt; 'copy.gif' &lt;br /&gt;
            ), &lt;br /&gt;
            'delete' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['delete'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=delete', &lt;br /&gt;
                'icon'                =&amp;gt; 'delete.gif', &lt;br /&gt;
                'attributes'          =&amp;gt; 'onclick=&amp;quot;if (!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\')) return false; Backend.getScrollOffset();&amp;quot;' &lt;br /&gt;
            ), &lt;br /&gt;
            'show' =&amp;gt; array &lt;br /&gt;
            ( &lt;br /&gt;
                'label'               =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['show'], &lt;br /&gt;
                'href'                =&amp;gt; 'act=show', &lt;br /&gt;
                'icon'                =&amp;gt; 'show.gif' &lt;br /&gt;
            ) &lt;br /&gt;
        ) &lt;br /&gt;
    ), &lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; 'partnernachname,partnervorname;partnerinnachname,partnerinvorname' &lt;br /&gt;
    ), &lt;br /&gt;
    // Subpalettes &lt;br /&gt;
    'subpalettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        ''                            =&amp;gt; '' &lt;br /&gt;
    ), &lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'partnernachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'maxlength'=&amp;gt;64) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnervorname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnervorname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnerinnachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinnachname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnerinvorname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinvorname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ) &lt;br /&gt;
    ) &lt;br /&gt;
);  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Verwirrung im DCA-Land==&lt;br /&gt;
Nachdem ich einige Testpaare in meine &amp;quot;Minimalmaske&amp;quot; eingetragen habe, stelle ich fest, dass es nicht ganz so aussieht, wie ich es gerne hätte.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_006.png]]&lt;br /&gt;
&lt;br /&gt;
Für jeden Herrennachnamen gibt es eine eigene Gruppenüberschrift. Das ist irgendwie suboptimal, und verschwendet Platz. Ich hätte gerne keine Gruppenüberschriften, oder nur &amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;, &amp;quot;C&amp;quot;, usw...Ich vermute, dass das mit dem Eintrag ''['list']['sorting']['flag']'' zusammenhängt, den ich auf &amp;quot;1&amp;quot; hatte, laut Referenz ''Sort by initial letter ascending'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // List &lt;br /&gt;
    'list' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'sorting' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'mode'                    =&amp;gt; 1, &lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname', 'partnervorname', 'partnerinnachname', 'partnerinvorname'), &lt;br /&gt;
            'flag'                    =&amp;gt; 1 &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich spiele also etwas mit ''flag'' herum, und stelle fest: Irgendwie beeinflusst das garnix. &lt;br /&gt;
*  2 = ''Sort by initial letter descending'', &lt;br /&gt;
*  3 = ''Sort by initial two letters ascending'', &lt;br /&gt;
*  4 = ''Sort by initial two letters descending'', &lt;br /&gt;
* 11 = ''Sort ascending'' oder &lt;br /&gt;
* 12 = ''Sort descending'' &lt;br /&gt;
machen in meiner Auflistung nirgendwo irgendeinen Unterschied. Immer wird stur ''ascending'' in der Reihenfolge meiner Sortierfelder sortiert, und für jeden &amp;quot;Unique&amp;quot; Herrennachnamen gibt es eine Gruppenüberschrift.&lt;br /&gt;
 &lt;br /&gt;
In meiner Verzweifelung setze ich ''['list']['sorting']['mode']'' auf 0, laut Referenz ''Records are not sorted''. Das Ergebnis sieht so aus&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_007.png]]&lt;br /&gt;
&lt;br /&gt;
Immerhin die Gruppenüberschriften weg...und stur ''ascending'' nach meinen Sortierfeldern sortiert. Fast schon unnötig zu erwähnen, dass ''flag'' auch hier keine Wirkung zu haben scheint.&lt;br /&gt;
&lt;br /&gt;
Um das Sortieren vielleicht &amp;quot;von Hand&amp;quot; steuern zu können, füge ich streng nach Referenz die Zeile&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'panelLayout'             =&amp;gt; 'search,sort,filter'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
hinzu in der Erwartung, dass mir dann in der Übersicht die entsprechenden Optionen angeboten werden. Leider - nichts. Die Übersichtsliste der Turnierpaare verändert sich überhaupt nicht.&lt;br /&gt;
&lt;br /&gt;
Meine ''['list']['sorting']''-Sektion sieht nun so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'sorting' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'mode'                    =&amp;gt; 0, &lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname', 'partnervorname', 'partnerinnachname', 'partnerinvorname'), &lt;br /&gt;
            'flag'                    =&amp;gt; 1, &lt;br /&gt;
            'panelLayout'             =&amp;gt; 'search,sort,filter' &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Jemand eine Ahnung, warum das Verhalten so ist, bzw. warum mich die Referenz für die DCA-Records so im Stich lässt?&lt;br /&gt;
Danke...&lt;br /&gt;
&lt;br /&gt;
==Leichte Entwirrung im DCA-Land==&lt;br /&gt;
Lösung gefunden! Bei den einzelnen ''field''-Beschreibungen muss noch die Freigabe zum Sortieren, Filtern und Suchen gegeben werden. Das sieht jetzt so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'partnernachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'filter'                  =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 1, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'maxlength'=&amp;gt;64) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnervorname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnervorname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnerinnachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinnachname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'filter'                  =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 1, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ), &lt;br /&gt;
        'partnerinvorname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinvorname'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength'=&amp;gt;64&lt;br /&gt;
) &lt;br /&gt;
        ) &lt;br /&gt;
    )  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit Ergebnis:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_008.png]]&lt;br /&gt;
&lt;br /&gt;
Schon besser, auch wenn die Dropdown-Liste hinter ''Suchen:'' noch leer ist. Vielleicht liegt das an den noch fehlenden Feld-Labels in den Sprachdateien. Nur warum man ''flag'' bei den einzelnen Fields und nochmal global angeben muss, das will ich noch nicht verstehen...&lt;br /&gt;
&lt;br /&gt;
Ergänzung: Und wenn ich ''['sorting']['mode']'' auf 2 setze, dann kann ich sogar mein Sortierfeld auswählen....sehr schön...&lt;br /&gt;
&lt;br /&gt;
==DCA-Polishing==&lt;br /&gt;
Nachdem also die leichten Verwirrungen rund um den DCA-Record beseitigt sind, geht es weiter damit, die Backend-&amp;quot;Maske&amp;quot; für die ''tl_gw_turnierpaare''-Tabelle zu definieren und zu &amp;quot;polieren&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Zu jedem Feld lege ich einen Verweis auf den Erklärungs-Text an, der unter dem Eingabefeld angezeigt wird, z.B. für das ''partnernachname''-Feld im Abschnitt ''['fields']['partnernachname']'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname_explanation'],  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der entsprechende Text muss in den Sprachfiles natürlich noch eingetragen werden - später.&lt;br /&gt;
&lt;br /&gt;
Außerdem ergänze ich den ''eval''-Wert meiner bisherigen 4 Eingabefelder um den Wert'' 'minlength' =&amp;gt; 1'', um bei den namen eine Mindestlänge zu erzwingen (Beim Wert 1 wahrscheinlich überflüssig, aber egal).&lt;br /&gt;
&lt;br /&gt;
Bei dem Nachnamen des Partners und der Partnerin ergänze ich außerdem '''tl_class' =&amp;gt; 'w50'''. Das sorgt dafür, dass zwei Felder nebeneinander dargestellt werden. Das Feld mit der w50-Klasse links, das darauffolgende rechts. Dadurch werden Nachname und Vorname jeder Person nebeneinander in einer Zeile dargestellt.&lt;br /&gt;
&lt;br /&gt;
Meine Einstellungen für das ''partnernachname''-Feld sehen jetzt so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Fields &lt;br /&gt;
    'fields' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        'partnernachname' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname_explanation'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'search'                  =&amp;gt; true, &lt;br /&gt;
            'sorting'                 =&amp;gt; true, &lt;br /&gt;
            'filter'                  =&amp;gt; true, &lt;br /&gt;
            'flag'                    =&amp;gt; 1, &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'minlength' =&amp;gt; 1, 'maxlength'=&amp;gt;64, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wo ich gerade noch optisch etwas aufräume, baue ich den Eintrag ''default'' unter ''palettes'' so um:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname;' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''{name_legend}'' legt die Überschrift für die &amp;quot;Palette&amp;quot; fest (also die Felder bis zum nächsten Semikolon). Der Wert muss später im Sprachenfile definiert werden. Ich habe nun alle 4 Textfelder in einer Palette. Optisches Ergebnis:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_009.png]]&lt;br /&gt;
&lt;br /&gt;
Wenn man sich &amp;quot;vernünftige&amp;quot; Überschriften aus dem Sprachfile dazu vorstellt, schon mal ganz OK :-).&lt;br /&gt;
&lt;br /&gt;
Nun geht es um die noch fehlenden Tabellenfelder.&lt;br /&gt;
&lt;br /&gt;
Zunächst kommt ''startgruppe'', das bezeichnet die Altersklasse des Paars. Das Feld soll ''mandatory'' sein, aber auch eine &amp;quot;leere Option&amp;quot; erlauben. Ich will als Ausnahme auch eine Mannschaft in die Paarliste eingeben können, und Mannschaften haben keine Altersklasse. Mein Code für das ''field'' sieht so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'startgruppe' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startgruppe'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startgruppe_explanation'],&lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'options'                 =&amp;gt; array('KIN I','KIN II', 'JUN I', 'JUN II', 'JUG', 'HGR', 'HGR II', 'SEN I', 'SEN II', 'SEN III', 'SEN IV'), &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'includeBlankOption' =&amp;gt; true) &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich wähle also ein ''select'', also eine Drop-Down-Box. In ''options'' liste ich die möglichen Altersgruppen auf, im ''eval''-Bereich gebe ich noch an, dass eine leere Option hinzugefügt werden soll.&lt;br /&gt;
&lt;br /&gt;
Dann kommen ''startklasselatein'' und ''startklassestandard''. Inhaltlich kann in beiden Feldern dasselbe drinstehen, darum ist es fast nur Copy&amp;amp;Paste für das zweite Feld. Die Definition sieht so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'startklasselatein' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklasselatein'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklasselatein_explanation'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'select', &lt;br /&gt;
            'options'                 =&amp;gt; array('E','D', 'C', 'B', 'A', 'S', 'PRO', 'LL', 'OL', 'RL', '2. BL', '1. BL'), &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'includeBlankOption' =&amp;gt; true, 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auch hier wieder eine Drop-Down-Box mit Optionen und Möglichkeit der &amp;quot;leeren Option&amp;quot;. Durch ''tl_class =&amp;gt; w50'' wird die Drop-Down-Box nach links gerückt, so dass rechts daneben noch die gleichartige Box für ''startklassestandard'' passt. Die hat natürlich KEIN ''tl_class =&amp;gt; w50''!&lt;br /&gt;
&lt;br /&gt;
Eigentlich müsste ich prüfen, dass entweder in ''startklasselatein'' oder ''startklassestandard'' ein Wert ausgewählt ist (also nicht in beiden Feldern die leere Option gewählt wurde), aber das bürde ich zunächst mal dem User auf, vielleicht ergänze ich hier später eine Validation durch einen Hook.&lt;br /&gt;
&lt;br /&gt;
Zur Motivation will ich meine drei neuen Felder auch in im backend sehen, dazu muss ich sie zur Liste der Paletten hinzufügen. Ich packe sie in eine eigene Palette mit Überschrift.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname;&lt;br /&gt;
{classes_legend},startgruppe,startklasselatein,startklassestandard' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ergebnis:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_010.png]]&lt;br /&gt;
&lt;br /&gt;
Weiter geht's, jetzt folgen die Felder ''aktiv'', ''aktivseit'' und ''aktivbis''.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'aktiv' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktiv'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktiv_explanation'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true, 'isBoolean' =&amp;gt; true) &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''Aktiv'' wird eine Checkbox. Ich weiß zwar nicht, was es für eine Bedeutung hat, aber da eine CheckBox immer &amp;quot;Boolean&amp;quot; ist, setze ich in ''eval'' ''isBoolean =&amp;gt; true''.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'aktivseit' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivseit'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivseit_explanation'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 4, 'maxlength' =&amp;gt; 4, 'rgxp' =&amp;gt; 'digit', 'tl_class' =&amp;gt; 'w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'aktivbis' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivbis'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivbis_explanation'],&lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 4, 'maxlength' =&amp;gt; 4, 'rgxp' =&amp;gt; 'digit') &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
''aktivseit'' und ''aktivbis'' sollen nur eine Jahreszahl enthalten. Darum setze ich Minimal- und Maximallänge auf 4 und lasse durch ''rgxp'' nur Zahlen zu. Man hätte auch eine Dropdown-Box mit Jahreszahlen drin nehmen können. Ich denke beides hat Vor- und Nachteile. Sich durch DropDown-Boxen zu scrollen, die bei &amp;quot;1900&amp;quot; anfangen, wenn man nach &amp;quot;2004&amp;quot; will, ist auch kein Vergnügen. Das erste Feld setze ich mit ''tl_class =&amp;gt; w50'' nach links, um das zweite Feld daneben darstellen zu können.&lt;br /&gt;
&lt;br /&gt;
Ich ergänze die Paletten-Definition um&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{aktiv_legend:hide},aktiv,aktivseit,aktivbis;  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da die Felder nicht so oft editiert werden, schließe ich die Palette defaultmäßig.&lt;br /&gt;
&lt;br /&gt;
Nun kommt schon ein kleiner Sonderfall: ''password''. Dies soll das Paar-Passwort sein, was zum Eintragen von Turnierergebnissen oder geänderten persönlichen Daten im Frontend dient. Ich will das nur in eigenen PHP-Skripten nutzen, von daher habe ich hier alle Freiheiten, wie ich das realisiere.&lt;br /&gt;
&lt;br /&gt;
Ich möchte gerne, dass der Sportwart in diesem Feld ein Klartextpasswort eingeben kann. In die Datenbank soll aber nur der MD5-Hash des Passworts gelangen. Momentan plane ich, dass in dem Textfeld einfach der MD5-Hash angezeigt wird, wenn man aber etwas in dieses Feld eingibt, dass es dann aber durch einen Hook in den Hash umgewandelt wird, bevor es in der Datenbank gespeichert wird. Um die Realisation kümmere ich mich später. Erstmal soll es ein ganz normales Text-Feld sein:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'password' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['password'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['password_explanation'], &lt;br /&gt;
            'exclude'                 =&amp;gt; false, &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'minlength' =&amp;gt; 1, 'maxlength' =&amp;gt; 64) &lt;br /&gt;
        )  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dieses Feld soll (alleine) in einer eigenen Palette stehen, darum ergänze ich die Palettendefinition um:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{password_legend:hide},password;  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zwischenstand der Backend-Maske:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_011.png]]&lt;br /&gt;
&lt;br /&gt;
Und nochmal die gesamte Paletten-Definition:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname;&lt;br /&gt;
{classes_legend},startgruppe,startklasselatein,startklassestandard;{aktiv_legend:hide},aktiv,aktivseit,aktivbis;{password_legend:hide},password;' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Leider ist damit schon wieder das Ende meiner zur Verfügung stehenden Zeit erreicht (Sorry, wenn es zu langsam voran geht). Bald geht es weiter.&lt;br /&gt;
&lt;br /&gt;
== Ein Bug, ein Bug!==&lt;br /&gt;
Nachdem man jetzt Startklassen eingeben, entdecke ich natürlich gleich einen Bug, und zwar in ''['list']['label']['fields']''.&lt;br /&gt;
&lt;br /&gt;
VORHER (falsch):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname','partnervorname','partnerinnachname','partnerinvorname','startgruppe','startklassestd','startklasselat'),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
NACHHER (richtig):&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'fields'                  =&amp;gt; array('partnernachname','partnervorname','partnerinnachname','partnerinvorname','startgruppe','startklassestandard','startklasselatein'),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
D.h. die beiden Felder für die Startklasse Standard und Latein waren falsch benannt. Sorry.&lt;br /&gt;
&lt;br /&gt;
Und weiter geht es mit Bugs:&lt;br /&gt;
Wenn ich bei Feldern, die eine &amp;quot;leere Option&amp;quot; zulassen, trotzdem in '''eval' mandatory =&amp;gt; true'' fordere, kann die leere Option nicht ausgewählt werden. Gut, irgendwie auch logisch. Aus diesem Grund setze ich bei ''startgruppe'', ''startklasselatein'' und ''startklassestandard'' &amp;quot;'''mandatory' =&amp;gt; false''&amp;quot;, um auch die leere Option zuzulassen.&lt;br /&gt;
&lt;br /&gt;
Und letzter kleiner Fehler:&lt;br /&gt;
Im ''format''-String für die Zeilen in der Übersicht der Turnierpaare ''['list']['label']['format']'' ist LAT und STD vertauscht, ich drehe das um. Neu:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'format'                  =&amp;gt; '%s, %s und %s, %s - %s %s STD / %s LAT'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==Nochmals anders==&lt;br /&gt;
Tjaja, wie das bei so einem Tagebuch im Gegensatz zum &amp;quot;durchgeplanten und polierten&amp;quot; Tutorial so ist: Ich habe mir nochmal was anders überlegt.&lt;br /&gt;
&lt;br /&gt;
Ich habe mich entschlossen, die Felder ''startklasselatein'' und ''startklassestandard'' doch ''mandatory'' zu machen, aber als Option eine Leer-Option &amp;quot;-&amp;quot; hinzuzufügen. So ist der Benutzer gezwungen, explizit anzugeben, dass ein Paar keine Startklasse in einer der beiden Sektionen hat, und in meiner Paarübersicht sieht es besser aus, wenn z.B. vor &amp;quot;LAT&amp;quot; noch ein Strich steht, statt einfach garnichts.&lt;br /&gt;
&lt;br /&gt;
Bei beiden Feldern sieht der Eintrag in ''['fields']'' jetzt also so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'options'                 =&amp;gt; array('-', 'E','D', 'C', 'B', 'A', 'S', 'PRO', 'LL', 'OL', 'RL', '2. BL', '1. BL'), &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;true)  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dann habe ich noch entdeckt, dass man eine Checkbox nicht ''mandatory'' machen darf, weil dann MUSS sie nämlich angehakt werden. Ist irgendwie suboptimal. Also nochmal den Eintrag ''['fields']['aktiv']['eval']'' geändert auf:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true)  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und schließlich habe ich den Format-String für die Turnierpaar-Übersicht nochmal überarbeitet. Damit die relevantesten Elemente hervorstechen gebe ich die Nachnamen der Partner fett aus, ebenso die Startgruppe. Die Startklassen zusätzlich in orange (Standard) und rot (Latein). Die Startpässe der Paare in der jeweiligen Sektion haben die gleichen Farben, so dass dies für den Eingeweihten eine natürliche Assoziation ist.&lt;br /&gt;
&lt;br /&gt;
''['list']['label']['format']'' lautet jetzt:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            'format'                  =&amp;gt; '&amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt;, %s und &amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;%s&amp;lt;/span&amp;gt;, %s - &amp;lt;span style=&amp;quot;font-weight: bold; margin-left: 5px&amp;quot;&amp;gt;%s &amp;lt;span style=&amp;quot;color: orange; margin-left: 5px;&amp;quot;&amp;gt;%s STD&amp;lt;/span&amp;gt; / &amp;lt;span style=&amp;quot;color: red;&amp;quot;&amp;gt;%s LAT&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und sieht so aus:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_012.png]]&lt;br /&gt;
&lt;br /&gt;
Aber im nächsten Post geht es endlich mit den restlichen Feldern der ''tl_gw_turnierpaare''-Tabelle weiter.&lt;br /&gt;
==DCA - Almost there==&lt;br /&gt;
Schritt 4 scheint kein Ende zu nehmen. Wie erwartet erweist sich das Thema &amp;quot;DCA&amp;quot; als harter Brocken.&lt;br /&gt;
&lt;br /&gt;
Zunächst geht es weiter mit den restlichen Feldern der ''tl_gw_turnierpaare''-Tabelle. Für Anschrift, Telefonnummer, Fax, Mobilnummer, Email-Adresse und Homepage gibt es jeweils ein Flag, ob es im öffentlichen Profil angezeigt werden soll. Ist es nicht gesetzt, sind die Daten nur im Backend sichtbar. So kann der Sportwart das Paar evtl. erreichen, falls notwendig&lt;br /&gt;
&lt;br /&gt;
Statt die Anschrift in Straße, PLZ, Ort, usw. aufzusplitten, habe ich hierfür eine ''textarea'' vorgesehen. Im DCA sieht das so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'anschrift' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['anschrift'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['anschrift_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'textarea', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'cols' =&amp;gt; 40, 'rows' =&amp;gt; 5) &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alles wie gehabt, zusätzlich geben ''cols'' und ''rows'' die Spalten und Zeilen des Eingabebereichs an. &lt;br /&gt;
&lt;br /&gt;
Die Definition für das Flag, ob die Anschrift öffentlich angezeigt werden soll, ist so wie beim Feld ''aktiv'':&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'zeigeanschrift' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeanschrift'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeanschrift_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true) &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nicht Besonderes!&lt;br /&gt;
Die Felder für Telefon, Fax, Mobilnummer, EMail und Homepage sind jeweils Textfelder, denen ich je nach Art die passende Regular Expression zur Überprüfung der Inhalte zuweise. Zusätzlich hat jedes Feld die &amp;quot;Anzeigen&amp;quot;-Checkbox:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'telefon' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['telefon'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['telefon_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength' =&amp;gt; 32, 'rgxp' =&amp;gt; 'phone') &lt;br /&gt;
        ), &lt;br /&gt;
        'zeigetelefon' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigetelefon'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigetelefon_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true, 'tl_class' =&amp;gt; 'clr m12 w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'fax' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['fax'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['fax_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength' =&amp;gt; 32, 'rgxp' =&amp;gt; 'phone') &lt;br /&gt;
        ), &lt;br /&gt;
        'zeigefax' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigefax'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigefax_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true, 'tl_class' =&amp;gt; 'clr m12 w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'mobil' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['mobil'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['mobil_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength' =&amp;gt; 32, 'rgxp' =&amp;gt; 'phone') &lt;br /&gt;
        ), &lt;br /&gt;
        'zeigemobil' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigemobil'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigemobil_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true, 'tl_class' =&amp;gt; 'clr m12 w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'email' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['email'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['email_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength' =&amp;gt; 32, 'rgxp' =&amp;gt; 'email') &lt;br /&gt;
        ), &lt;br /&gt;
        'zeigeemail' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeemail'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeemail_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true, 'tl_class' =&amp;gt; 'clr m12 w50') &lt;br /&gt;
        ), &lt;br /&gt;
        'homepage' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['homepage'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['homepage_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'text', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'maxlength' =&amp;gt; 32, 'rgxp' =&amp;gt; 'url') &lt;br /&gt;
        ), &lt;br /&gt;
        'zeigehomepage' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigehomepage'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigehomepage_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'checkbox', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'isBoolean' =&amp;gt; true, 'tl_class' =&amp;gt; 'clr m12 w50') &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die ''tl_class''-Werte sind so gewählt, dass jede &amp;quot;Anzeigen&amp;quot;-Checkbox links in einer Reihe mit dem entsprechenden Textfeld (rechts) in einer Zeile steht. Ich hätte es gerne andersrum gehabt, also Textfeld links, Checkbox rechts, aber trotz viel experimentieren mit den ''tl_class''-Werten ist es mir nicht gelungen, das Layout sah immer &amp;quot;zerschossen&amp;quot; aus.&lt;br /&gt;
&lt;br /&gt;
Den Wert ''['palettes']['default']'' ergänze ich noch um&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
'{contact_legend:hide},zeigeanschrift,anschrift,zeigetelefon,telefon,zeigefax,fax,zeigemobil,mobil,zeigeemail,email,zeigehomepage,homepage;'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ergebnis:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_013.png]]&lt;br /&gt;
&lt;br /&gt;
''Beschreibung'' ist eine Textarea, die in eigener Palette angezeigt werden soll. Einzige Besonderheit ist hier, dass ich HTML im Inhalt zulassen will.&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'beschreibung' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['beschreibung'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['beschreibung_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'textarea', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'cols' =&amp;gt; 80, 'rows' =&amp;gt; 20, 'allowHtml' =&amp;gt; true) &lt;br /&gt;
        ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Schließlich fehlt noch das Bild. Hier wollte ich eine Bilder-Auswahl wie im Content-Element &amp;quot;Bild&amp;quot; haben. Ich habe eine Weile herumexperimentiert, insbesondere mit dem Feldtyp &amp;quot;radioTable&amp;quot; (Der aber ganz falsch ist, wie mir jetzt klar ist). Lösung brachte dann ein Blick in das [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorial], wo auch so eine Bilderauswahl drin ist. Der richtige DCA-Eintrag lautet:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        'bild' =&amp;gt; array &lt;br /&gt;
        ( &lt;br /&gt;
            'label'                   =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['bild'], &lt;br /&gt;
            'explanation'             =&amp;gt; &amp;amp;$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['bild_explanation'], &lt;br /&gt;
            'inputType'               =&amp;gt; 'fileTree', &lt;br /&gt;
            'eval'                    =&amp;gt; array('mandatory'=&amp;gt;false, 'files'=&amp;gt;true, 'fieldType'=&amp;gt;'radio', 'filesOnly' =&amp;gt; true, 'extensions' =&amp;gt; 'jpg,jpeg,png,gif', 'path' =&amp;gt; 'tl_files/GW/Bilder_Turnierpaare/') &lt;br /&gt;
        )  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typ ist also ein ''fileTree'', in dem man mittels Radiobutton EIN File auswählen kann (''fieldType =&amp;gt; radio''), in dem Dateien mit den Erweiterungen jpeg,jpg,png und gif angezeigt werden (''extensions''), in dem Unterverzeichnisse UND Dateien angezeigt werden (''files =&amp;gt; true'', sonst werden NUR Verzeichnisse angezeigt), und in dem man mittels des Radiobuttons auch ausschließlich Dateien auswählen kann, KEINE Unterverzeichnisse (''filesOnly =&amp;gt; true''). Zusätzlich gebe ich den &amp;quot;Basis-Pfad&amp;quot; an, aus dem man auswählen kann (''path''). Wobei der natürlich bei Jedem anders heißen kann...Also eigentlich nicht so toll. Muss nochmal drüber nachdenken.&lt;br /&gt;
&lt;br /&gt;
Noch die Palettendefinition erweitern um&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
'{beschreibung_legend:hide},beschreibung;{bild_legend:hide},bild;'  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
und wir landen hier:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_014.png]]&lt;br /&gt;
&lt;br /&gt;
Damit bin ich im Prinzip mit der Maskendefinition für diese Tabelle fertig, abgesehen vom Hook für das MD5-Hashing meines Passworts. Das verschiebe ich erstmal auf später :-).&lt;br /&gt;
&lt;br /&gt;
Folgende &amp;quot;Probleme&amp;quot; habe ich noch: Meine Palettendefinition sieht insgesamt so aus:&lt;br /&gt;
&lt;br /&gt;
PHP-Code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Palettes &lt;br /&gt;
    'palettes' =&amp;gt; array &lt;br /&gt;
    ( &lt;br /&gt;
        '__selector__'                =&amp;gt; array(''), &lt;br /&gt;
        'default'                     =&amp;gt; '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname;'.'{classes_legend},startgruppe,startklasselatein,startklassestandard;'.'{aktiv_legend:hide},aktiv,aktivseit,aktivbis;password_legend:hide},password;'.'{contact_legend:hide},zeigeanschrift,anschrift,zeigetelefon,telefon,zeigefax,fax,zeigemobil,mobil,zeigeemail,email,zeigehomepage,homepage;'.'{beschreibung_legend:hide},beschreibung;{bild_legend:hide},bild;' &lt;br /&gt;
    ),  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Eigentlich erwarte ich, dass nur die oberste Palette geöffnet ist, und alle folgenden geschlossen. Komischerweise sind beim Editieren bestehender Einträge und auch bei der Neuanlage alle geöffnet bis auf ''password'' und ''beschreibung''. Ich kann nicht verstehen, wieso. Kann mich jemand schlau machen?&lt;br /&gt;
&lt;br /&gt;
Die Eigenschaft ''exclude'' im Abschnitt ''fields'' soll steuern, ob das jeweilige Feld in der Usergruppenverwaltung spezifisch für einzelne Gruppen (de)aktivierbar ist. ''Bei exclude =&amp;gt; true'' soll das Feld in der Usergruppenverwaltung erscheinen, bei ''false'' soll es dort nicht erscheinen und immer sichtbar sein (für die Gruppen, die das Backend-Modul überhaupt freigegeben haben).&lt;br /&gt;
&lt;br /&gt;
Das Verhalten scheint aber ein anderes zu sein: Egal ob ich ''exclude true'' oder ''false'' zuweise, erscheint das Feld in der Usergruppenverwaltung. Nur wenn ich ''exclude'' ganz weglasse, erscheint es dort nicht. Ein Bug? Keine Ahnung. Zumindest ist es in der Referenz anders beschrieben. Da ich diese Steuerung auf Feldebene nicht brauche, sondern das ganze Backendmodul nur einer bestimmten Usergruppe freischalten möchte, habe ich die ''exclude''-Eigenschaft aus allen Felddefinitionen entfernt. &lt;br /&gt;
&lt;br /&gt;
Mein &amp;quot;Traum&amp;quot; wäre, dass man, falls ein Bild schon ausgewählt ist im Filetree man sofort dieses Bild sieht, statt erst den Filetree öffnen zu müssen, um zu sehen ob irgendwo der Radiobutton gesetzt ist. So kann man beim Öffnen eines Datensatzes nicht schnell sehen, ob ein Paar ein Bild zugewiesen hat, oder nicht. Aber ich glaube, das ist so (noch) nicht vorgesehen.&lt;br /&gt;
&lt;br /&gt;
So, das sollte das Ende von Schritt 4 gewesen (puh),. Um die Maske zu vervollständigen werde ich mit der Definition der Texte in den Sprachfiles weitermachen.&lt;br /&gt;
&lt;br /&gt;
=Language Files=&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_015.png]]&lt;br /&gt;
&lt;br /&gt;
=Von Callbacks und Subpaletten=&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_016.png]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:Attachment_017.png]]&lt;br /&gt;
&lt;br /&gt;
=Endlich Frontend!=&lt;br /&gt;
==Ein wenig Finetuning==&lt;br /&gt;
=Parameter fürs Modul=&lt;br /&gt;
==Parameter fürs Modul, die Zweite==&lt;br /&gt;
=Details, Details, Details=&lt;br /&gt;
=Etwas Feinschliff=&lt;br /&gt;
=Die zweite Tabelle=&lt;br /&gt;
=Callback-Magie=&lt;br /&gt;
=Frontendmodul Meldeliste=&lt;br /&gt;
==JOIN-Power==&lt;br /&gt;
=Downloads=&lt;br /&gt;
dl1ely hat eine gezippte Version seiner Extension zum Download zur Verfügung gestellt, der Stand ist vom 29.05.2010. &lt;br /&gt;
Diese Datei entpacken Sie bitte in den TL/contao-Ordner ''/system/modules/''. &lt;br /&gt;
&lt;br /&gt;
[http://dl.dropbox.com/u/804662/gw_turnierpaare_20100529.zip Quelltext des Moduls]&lt;br /&gt;
&lt;br /&gt;
Schnippsel hat aus den Forumsbeiträgen bis #104 eine PDF-Datei erstellt, die minimal gekürzt ist. Insbesondere alle forumsspezifischen Details (z.B. Fotos der Poster etc.), Anreden und Grußformeln sowie die Lobeshymnen (&amp;quot;Ich finde dein Tutorial gaaaaaanz toll!&amp;quot;) wurden entfernt. Trotzdem hat die Datei eine Größe von ca. 1,5 MB und umfasst ca. 125 Seiten!&lt;br /&gt;
&lt;br /&gt;
[[http://de.contaowiki.org/images/de/d/d2/Tagebuch_einer_Extension-Entwicklung_-_bis_104.pdf PDF-Datei mit Forumsbeiträgen]]&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Tagebuch_einer_Extension-Entwicklung</id>
		<title>Tagebuch einer Extension-Entwicklung</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Tagebuch_einer_Extension-Entwicklung"/>
				<updated>2010-07-07T09:41:33Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: hat „Tagebuch einer Extension-Entwicklung“ nach „TEE-00 Vorbemerkung“ verschoben:&amp;amp;#32;Das Thema wurde wegen des grossen Umfangs auf mehrere Seiten aufgeteilt und in eine eigene (Unter-)Kategorie überführt.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#WEITERLEITUNG [[TEE-00 Vorbemerkung]]&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_38.png</id>
		<title>Datei:Gw turnierpaare 38.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_38.png"/>
				<updated>2010-07-06T08:20:54Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-07&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-07&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_37.png</id>
		<title>Datei:Gw turnierpaare 37.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_37.png"/>
				<updated>2010-07-06T08:20:28Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-07&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-07&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_36.png</id>
		<title>Datei:Gw turnierpaare 36.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_36.png"/>
				<updated>2010-07-06T08:19:20Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-07&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-07&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_35.png</id>
		<title>Datei:Gw turnierpaare 35.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_35.png"/>
				<updated>2010-07-06T08:19:00Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-07&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-07&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_34.png</id>
		<title>Datei:Gw turnierpaare 34.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_34.png"/>
				<updated>2010-07-06T08:18:36Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-06&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-06&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_33.png</id>
		<title>Datei:Gw turnierpaare 33.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_33.png"/>
				<updated>2010-07-06T08:18:22Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-06&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-06&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_32.png</id>
		<title>Datei:Gw turnierpaare 32.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_32.png"/>
				<updated>2010-07-06T08:18:02Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-06&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-06&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_31.png</id>
		<title>Datei:Gw turnierpaare 31.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_31.png"/>
				<updated>2010-07-06T08:17:42Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-06&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-06&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_30.png</id>
		<title>Datei:Gw turnierpaare 30.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_30.png"/>
				<updated>2010-07-06T08:16:55Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-05&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-05&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_29.png</id>
		<title>Datei:Gw turnierpaare 29.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_29.png"/>
				<updated>2010-07-06T08:16:26Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-05&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-05&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_28.png</id>
		<title>Datei:Gw turnierpaare 28.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_28.png"/>
				<updated>2010-07-06T08:16:06Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-05&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-05&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_27.png</id>
		<title>Datei:Gw turnierpaare 27.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_27.png"/>
				<updated>2010-07-06T08:15:27Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-05&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-05&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_26.png</id>
		<title>Datei:Gw turnierpaare 26.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_26.png"/>
				<updated>2010-07-06T08:14:58Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-05&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-05&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_25.png</id>
		<title>Datei:Gw turnierpaare 25.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_25.png"/>
				<updated>2010-07-06T08:14:27Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-05&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-05&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_24.png</id>
		<title>Datei:Gw turnierpaare 24.png</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_24.png"/>
				<updated>2010-07-06T08:12:53Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-03&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-03&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	<entry>
		<id>https://de.contaowiki.org/Datei:Gw_turnierpaare_23.jpg</id>
		<title>Datei:Gw turnierpaare 23.jpg</title>
		<link rel="alternate" type="text/html" href="https://de.contaowiki.org/Datei:Gw_turnierpaare_23.jpg"/>
				<updated>2010-07-06T08:12:11Z</updated>
		
		<summary type="html">&lt;p&gt;Schnippsel: TEE-Frontend-03&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TEE-Frontend-03&lt;/div&gt;</summary>
		<author><name>Schnippsel</name></author>	</entry>

	</feed>