Schritt 11: Die zweite Tabelle
Ich habe mich lange davor gedrückt, aber jetzt muss es an meine zweite Tabelle gehen: tl_gw_meldungen.
Meldungen sind Teilnahmen von Turnierpaaren an Turnieren. Sie bestehen aus dem Datum der Turnierteilnahme, dem Ort, 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), der Tanzart (Standard/Lateinamerikanisch), der Turnierart (Hier unterscheidet man "offene Turniere", "Einladungsturniere", "Landesmeisterschaften", "Deutsche Meisterschaften" usw), der Anzahl der gestarteten Paare, dem Platz (Da es geteilte Plätze wie 5.-7. geben kann gibt es "platz_von" und "platz_bis"), und einem Freitext als Bemerkung.
Soviel zur Domain specific knowledge.
Schauen wir uns nochmal die SQL-Definition in config/database.sql an:
Code:
--
-- Table `tl_gw_meldungen`
--
CREATE TABLE `tl_gw_meldungen` (
`id` int(10) unsigned NOT NULL auto_increment,
`pid` int(10) unsigned NOT NULL default '0',
`sorting` int(10) unsigned NOT NULL default '0',
`tstamp` int(10) unsigned NOT NULL default '0',
`datum` date NOT NULL default '2000-01-01',
`startgruppe` varchar(32) NOT NULL default '',
`startklasse` varchar(12) NOT NULL default '',
`lat_std` char(32) NOT NULL default '',
`turnierort` varchar(128) NOT NULL default '',
`turnierart` varchar(64) NULL default NULL,
`anzahlpaare` int(4) NULL default NULL,
`platz_von` int(4) NULL default NULL,
`platz_bis` int(4) NULL default NULL,
`bemerkung` text NULL,
PRIMARY KEY (`id`),
KEY `pid` (`pid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Die ersten 4 Felder sind ja so "default". Hier macht pid (Parent-ID) aber auch Sinn. Die Meldungen sind "Childs" 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.
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".
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.
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.
Ich brauche also eine weitere Seite im Backend, und modifiziere /system/modules/gw_turnierpaare/config/config.php auf:
PHP-Code:
// Back end module
$GLOBALS['BE_MOD']['content']['gw_turnierpaare'] = array
(
'tables' => array('tl_gw_turnierpaare'),
'icon' => 'system/modules/gw_turnierpaare/icons/turnierpaare.png'
);
$GLOBALS['BE_MOD']['content']['gw_meldungen'] = array
(
'tables' => array('tl_gw_meldungen'),
'icon' => 'system/modules/gw_turnierpaare/icons/meldeliste.png'
);
Also zwei hier formal getrennte Tabellen mit getrennten Backendseiten und verschiedenen Icons (meldeliste.png hänge ich hier an, das soll ein Siegerpodest darstellen).
Dann gehts an DCA für die Meldungstabelle, in /system/modules/gw_turnierpaare/dca/tl_gw_meldungen.php:
PHP-Code:
/**
* Table tl_gw_meldungen
*/
$GLOBALS['TL_DCA']['tl_gw_meldungen'] = array
(
// Config
'config' => array
(
'dataContainer' => 'Table',
'enableVersioning' => true,
),
Hier keine Besonderheiten, es ist eine Tabelle mit Versionierung...
PHP-Code:
// List
'list' => array
(
'sorting' => array
(
'mode' => 1,
'fields' => array('datum DESC', 'turnierort'),
'panelLayout' => '',
'flag' => 8,
),
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.
PHP-Code:
'label' => array
(
'fields' => array('datum', 'turnierort', 'turnierart', 'startgruppe','startklasse','lat_std','pid'),
'format' => '<span style="font-weight: bold;">%s</span>, %s (%s), %s %s %s - %s'
),
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.
PHP-Code:
'global_operations' => array
(
'all' => array
(
'label' => &$GLOBALS['TL_LANG']['MSC']['all'],
'href' => 'act=select',
'class' => 'header_edit_all',
'attributes' => 'onclick="Backend.getScrollOffset();"'
)
),
'operations' => array
(
'edit' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['edit'],
'href' => 'act=edit',
'icon' => 'edit.gif'
),
'copy' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['copy'],
'href' => 'act=copy',
'icon' => 'copy.gif'
),
'delete' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['delete'],
'href' => 'act=delete',
'icon' => 'delete.gif',
'attributes' => 'onclick="if (!confirm(\'' . $GLOBALS['TL_LANG']['MSC']['deleteConfirm'] . '\')) return false; Backend.getScrollOffset();"'
),
'show' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['show'],
'href' => 'act=show',
'icon' => 'show.gif'
)
)
),
Hier bleibt erstmal alles so, wie vom Extension Creator vorgegeben.
PHP-Code:
// Palettes
'palettes' => array
(
'__selector__' => array(''),
'default' => '{couple_legend},pid;{tournament_legend},datum,turnierort,turnierart,startgruppe,startklasse,lat_std;'
.'{result_legend},anzahlpaare,platz_von,platz_bis,bemerkung;'
),
// Subpalettes
'subpalettes' => array
(
'' => ''
),
Auch hier nichts spannendes: Eine normale Palette für alle Felder.
PHP-Code:
// Fields
'fields' => array
(
'pid' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['pid'],
'inputType' => 'select',
'foreignKey' => 'tl_gw_turnierpaare.partnernachname',
'search' => true,
'sorting' => true,
'eval' => array('mandatory'=>true)
),
pid soll ein Foreign Key in die Turnierpaare-Tabelle sein. mir 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.
PHP-Code:
'datum' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['datum'],
'inputType' => 'text',
'search' => true,
'sorting' => true,
'flag' => 11,
'eval' => array('mandatory'=>true, 'datepicker'=>$this->getDatePickerString(), 'tl_class'=>'w50 wizard', 'minlength' => 1, 'maxlength'=>64, 'rgxp' => 'date')
),
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.
PHP-Code:
'turnierort' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierort'],
'inputType' => 'text',
'search' => true,
'sorting' => true,
'flag' => 1,
'eval' => array('mandatory'=>true, 'minlength' => 1, 'maxlength'=>128, 'tl_class' => 'w50')
),
Nichts Besonderes hier...
PHP-Code:
'turnierart' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['turnierart'],
'inputType' => 'select',
'sorting' => false,
'options' => gwTurnierpaarliste::$TurnierArten,
'eval' => array('mandatory'=>false, 'includeBlankOption' => true, 'tl_class' => 'w50')
),
Ähnlich wie bei den Startgruppen und Klassen lagere ich die Optionen für "Turnierart" in meine Frontendklasse aus. Gefällt mir besser so, und ich kann es "Re-usen".
PHP-Code:
'startgruppe' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['startgruppe'],
'inputType' => 'select',
'sorting' => true,
'flag' => 1,
'options' => gwTurnierpaarliste::$StartGruppen,
'eval' => array('mandatory'=>false, 'includeBlankOption' => true, 'tl_class' => 'w50')
),
'startklasse' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['startklasse'],
'inputType' => 'select',
'sorting' => false,
'options' => gwTurnierpaarliste::$StartKlassen,
'eval' => array('mandatory'=>true, 'tl_class' => 'w50')
),
'lat_std' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['lat_std'],
'inputType' => 'select',
'sorting' => false,
'options' => gwTurnierpaarliste::$TanzArten,
'eval' => array('mandatory'=>true, 'tl_class' => 'w50')
),
Wie zuvor, normale Dropdownfelder, deren Optionen ich in der Frontendklasse gwTurnierpaarliste ablege, um sie von verschiedenen Bereichen aus nutzen zu können.
PHP-Code:
'anzahlpaare' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['anzahlpaare'],
'inputType' => 'text',
'eval' => array('mandatory'=>false, 'minlength' => 1, 'maxlength'=>4, 'rgxp' => 'digit')
),
'platz_von' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_von'],
'inputType' => 'text',
'eval' => array('mandatory'=>false, 'minlength' => 1, 'maxlength'=>4, 'rgxp' => 'digit', 'tl_class' => 'w50')
),
'platz_bis' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['platz_bis'],
'inputType' => 'text',
'eval' => array('mandatory'=>false, 'minlength' => 1, 'maxlength'=>4, 'rgxp' => 'digit', 'tl_class' => 'w50')
),
'bemerkung' => array
(
'label' => &$GLOBALS['TL_LANG']['tl_gw_meldungen']['bemerkung'],
'inputType' => 'textarea',
'eval' => array('mandatory'=>false, 'cols' => 80, 'rows' => 20, 'allowHtml' => false)
),
)
);
Auch hier eigentlich "Hausmannskost": 3 Felder für Zahlen und ein Textfeld für die Bemerkung.
/system/modules/gw_turnierpaare/gwTurnierpaarliste.php (das Frontend-Modul) erweitere ich noch um die Optionenlisten für Tanzart und Turnierart:
PHP-Code:
public static $TurnierArten = array('-', 'OT','ET', 'LM', 'DM', 'EM', 'WM');
public static $TanzArten = array('-', 'Std','Lat');
Zum ersten Testen füge ich zwei Testdatensätze in die Meldungstabelle ein. Ergebnis:
![](https://community.contao.org/de/attachment.php?attachmentid=1649&stc=1&d=1271095947)
Gut, die Tabellenheader sehen noch nicht so aus wie gewünscht, aber das ist Feinschliff. Die gewünschten Informationen (mit pid 7) werden angezeigt.
Wenn ich einen neuen Eintrag hinzufüge, sieht das so aus:
![](https://community.contao.org/de/attachment.php?attachmentid=1651&stc=1&d=1271096091)
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.
Mich wundert der "20.12.2000" 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.
Ich gebe also mal Daten ein:
![](https://community.contao.org/de/attachment.php?attachmentid=1652&stc=1&d=1271096301)
Und drücke auf Speichern- was sehe ich beim Datum:
![](https://community.contao.org/de/attachment.php?attachmentid=1653&stc=1&d=1271096393)
30.11.1999? Das habe ich im Datepicker aber nicht ausgewählt....auch eine manuelle Eingabe sorgt für das selbe 1999er-Ergebnis.
Und in der Übersichtstabelle dann das:
![](https://community.contao.org/de/attachment.php?attachmentid=1662&stc=1&d=1271163730)
0000-00-00...hm.
Das ist alles nicht so ermutigend. Ich habe die Konfiguration für das Datumsfeld bei tl_article.php abgeschaut, da funktioniert ja auch alles.
Erstmal Pause, demnächst geht es weiter.
Stefan
Lesezeichen