TEE-00 Vorbemerkung: Unterschied zwischen den Versionen

Aus Contao Community Documentation

K (Typo)
 
(4 dazwischenliegende Versionen von einem Benutzer werden nicht angezeigt)
Zeile 1: Zeile 1:
 
{{stub}}
 
{{stub}}
[[Category:Dev_HOWTOS]]
+
Tagebuch einer Extension-Entwicklung / Vorbemerkungen der Wiki-Autoren
{{AppliesTo|Ext1=Extension Creator|TLVersion=ab TL 2.8}}
+
[[Category:Tagebuch_einer_Extension-Entwicklung]]
=Vorbemerkung=
+
{{AppliesTo
Dieser Artikel nimmt einen sehr ausführlichen Forumsbeitrag aus dem Contao-Community-Forum ''Allgemeine Infos für Third-Party Extensions -> 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]]
+
|Ext1=Extension Creator
 +
|TLVersion=ab TL 2.8}}
  
Entgegen den Wiki-Gepflogenheiten ist dieser Artikel in der Ich-Form gehalten, da es sich um einen Erfahrungsbericht handelt.
+
=Vorbemerkungen=
=Allgemeine Hinweise=
+
* Die Artikel nehmen einen sehr ausführlichen Forumsthread aus dem Contao-Community-Forum ''Allgemeine Infos für Third-Party Extensions -> Entwickler-Tutorials'' auf, der unter dem Titel ''Tagebuch einer Extension-Entwicklung'' von dl1ely (Stefan) verfasst wurde.  
Ich möchte hier gerne eine Art "Tagebuch" einer Extension-Entwicklung schreiben. Ich besitze das TL-Buch, ich kenne das "Hello, World"-Beispiel, ich kenne das [http://dev.typolight.org/projects/typolight/wiki/TutorialsExtension CD-Collection-Tutorial], ich kenne das FlowPlayer-Beispiel.
+
+
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 "Anfängern" 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 "Tutorial", falls nicht, dann bitte ich um Verschiebung in die "Fragen"-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 "Tutorials" selbst nicht mehr weiter weiß.  
+
  
Vorneweg:
+
* 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.
TL = TYPOlight
+
FE = Frontend (Seite, die jeder Surfer sieht)
+
BE = Backend (Seite, die nur eingeloggte "Redakteure" sehen unter der /typolight URL)
+
  
Alles soll sich unter TL 2.8.0 abspielen, und ich werde den Extension Creator verwenden, um mir das "Skelett" der Extension zu erstellen.
+
* Die Originalbeiträge wurden redaktionell leicht überarbeitet. Dabei wurden neben forumspezifischen Besonderheiten auch Überleitungen, Anrede- und Grußformeln, Bewertungen ("Ich finde das Tutorial gaaaanz toll!") u.ä. entfernt.
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 "Studium".
+
  
=Anforderungen und Randbedingungen=
+
* An einigen Stellen wurden kleine Ergänzungen eingefügt.
Zunächst mal zum Hintergrund:
+
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.
+
+
Das Design steht noch nicht, erstmal soll die technische Funktionalität geschaffen werden. 95% der bisherigen Seiteninhalte lassen sich mit "TL-Bordmitteln" oder schon verfügbaren Extensions wie efg erschlagen. Allerdings gibt es auf der alten Seite einige "handgestrickte" PHP-Skripte, deren Funktionalität mehr oder weniger auf der neuen Seite erhalten bleiben soll.
+
  
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:
+
* Entgegen den Wiki-Gepflogenheiten sind die Artikel in der Ich-Form gehalten, da es sich um einen Erfahrungsbericht handelt.
  
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 "Visitenkarte" 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.
+
* 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.  
+
Für jedes Turnierpaar gibt es N "Meldungen", 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 "Meldung" in der Datenbank ein. Auf der sog. "Meldeliste" 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.
+
+
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).
+
+
Die Meldeliste dient also mehreren Zwecken:
+
* Rückmeldung vom Sportwart an die Paare, dass die Meldung beim Veranstalter erfolgt ist
+
* Außenwirkung für den Verein: Wie viele Paare haben wir, und wo starten sie
+
* Außenwirkung für die Tanzpaare selbst: Wie gut haben wir abgeschnitten
+
  
Übertragen auf die Tabellenstruktur handelt es sich also um die Tabelle der Turnierpaare, klassisch im BE durch ein BE-Modul gepflegt. Die Meldungen sind "Childs" der Turnierpaare, und sollten so auch im Backend angezeigt werden (Wie Artikel - Inhaltselemente). Zugriff auf das BE-Modul hat nur der Sportwart.
 
 
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.
 
 
Die Ausgabe der Daten im Frontend soll auf verschiedene Weisen geschehen:
 
  
* Modul ''Aktive Turnierpaare''
+
Und so ist das Tutorial aufgebaut:
  
* Modul ''Ehemalige Turnierpaare''
+
*TEE-00 Vorbemerkungen
  
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.
+
*[[TEE-01 Einleitung|TEE-01 Einleitung]]
 
+
*[[TEE-02 Extension Creator|TEE-02 Extension Creator]]
* Modul ''Meldeliste'' - Eine chronologisch absteigend sortierte Liste aller Melde-Einträge, Neueste also zuerst.
+
*[[TEE-03 Backend BE-Modul und SQL|TEE-03 Backend BE-Modul und SQL]]
 
+
*[[TEE-04 Backend DCA|TEE-04 Backend DCA]]
* Module/Formulare für Änderung der Paardaten im Frontend und zum Hinzufügen von Platzierung/Kommentar bei Meldungen
+
*[[TEE-05 Backend Language Files|TEE-05 Backend Language Files]]
 
+
*[[TEE-06 Backend Callbacks und Subpaletten|TEE-06 Backend Callbacks und Subpaletten]]
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.
+
*[[TEE-07 Frontend Simpel-Version|TEE-07 Frontend Simpel-Version]]
 
+
*[[TEE-08 Frontend Parametrisierung|TEE-08 Frontend Parametrisierung]]
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.
+
*[[TEE-09 Frontend Detailliste|TEE-09 Frontend Detailliste]]
 
+
*[[TEE-10 Frontend Feinschliff|TEE-10 Frontend Feinschliff]]
Coming up next: Extension-"Skelett" anlegen mit dem Extension-Creator.
+
*[[TEE-11 Backend Zweite Tabelle|TEE-11 Backend Zweite Tabelle]]
 
+
*[[TEE-12 Backend Callback-Magie|TEE-12 Backend Callback-Magie]]
==Diskussionsbeiträge aus dem Forum==
+
*[[TEE-13 Frontend Meldeliste|TEE-13 Frontend Meldeliste]]
{{Hinweis| Diskussionsbeiträge aus dem Forum einarbeiten!}}
+
*[[TEE-14 Downloads|TEE-14 Downloads]]
=Extension Creator=
+
*[[TEE-15 Werkzeuge|TEE-15 Werkzeuge]]
Also, los geht es mit dem Skelett für die geplante Extension. Ich verwende den Extension-Creator aus dem Extension-Repository.
+
 
+
* Titel: Es geht um Turnierpaar-"Verwaltung", und um Namenskonflikte zu vermeiden möchte ich gerne einen spezifischen Präfix nutzen: gw angelehnt an den Vereinsnamen "Grün-Weiß". Also: Titel = ''gw_turnierpaare''. An dieser Stelle bin ich mir noch nicht so sicher, wo dieser "Titel" überall erscheinen wird, und ob es deshalb ein beliebiger Text sein soll, oder eher ein "identifier", also z.b. ohne Leerzeichen u.ä. Sicherheitshalber gehe ich den Identifier-Weg. Besser hässlich als nicht-funktionierend.
+
 
+
* Ordnername: Ebenfalls ''gw_turnierpaare''.
+
 
+
* Autor, Copyright und Lizenz: Selbsterklärend
+
 
+
* Paket: Ein Paketname ist gefragt. Der Hilfetext unter dem Eingabefeld schlägt hilfreich "z.B. meinEigenesModul" 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 "Paketname", also ''GW''. Weitere vereinsspezifische Extensions würde ich dann in dasselbe Paket stecken.
+
 
+
* Ein Backend-Modul hinzufügen: Ja klar, schließlich sollen Daten im Backend bearbeitet werden. Also dort ein Häkchen.
+
 
+
* Backend-Klassen: Wenig hilfreicher Erklärungstext: "Hier können Sie eine kommagetrennte Liste der zu erstellenden Backend-Klassen eingeben." - 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.
+
 
+
* Backend-Tabellen: Das sind wohl meine Datentabellen, ich will eine für Turnierpaare, eine für Meldungen, also: ''tl_gw_turnierpaare,tl_gw_meldungen''.
+
 
+
* 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.
+
 
+
* Ein Frontend-Modul hinzufügen: Aber klar, die Daten sollen schließlich im Frontend visualisiert werden. Also Haken dran.
+
 
+
* 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.
+
 
+
* 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.
+
 
+
* 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.
+
 
+
* Sprachpakete erstellen: Natürlich. Auch wenn es wahrscheinlich niemand in Englisch benutzen wird, tut es mir aber auch nicht weh, also Sprachen = ''en,de''.
+
 
+
Dann "speichern und schließen", 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.
+
+
Und zwar:
+
 
+
* ''gwMeldeliste.php,gwTurnierpaarliste.php'': meine Frontendklassen
+
 
+
* ''config/config.php'' und ''config/database.sql'' (Letzteres für meine SQL-Tabellenstruktur)
+
 
+
* ''dca/tl_gw_turnierpaare.php'' und ''dca/tl_gw_meldungen.php'': Die DCA-Definitionen für meine Tabellen zur Bearbeitung im Backend
+
 
+
* ''languages/...'': Die Sprachfiles in en und de-Variante
+
 
+
* ''templates/...'': Die drei Frontend-Templates, die ich angegeben hatte
+
 
+
Im nächsten Schritt orientieren wir uns etwas und beginnen, die vorgegebenen Files zu modifizieren.
+
 
+
P.S.: Wenn die erfahrenen TL-Programmierer jetzt schon Gänsehaut haben: Sorry. Ich mache das zum ersten
+
Mal, und stelle mich nicht künstlich dumm an. Ich versuche so zu schildern, wie ich als Einsteiger die Sachen
+
sehe, was mich verwirrt usw...Bin für Verbesserungsvorschläge z.B. zu Namens-Schemata usw immer zu haben.
+
Genauso freue ich mich über Aufklärung zu Dingen, die ich selbst nicht verstehe...Backendklassen, Backend-
+
Templates, Frontend-Tabellen, Paket...
+
 
+
=Backend-Modul registrieren=
+
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.
+
 
+
Zunächst will ich mein Backend-Modul in TYPOlight bekannt machen. Dafür öffne ich ''/system/modules/gw_turnierpaare/config/config.php''.
+
 
+
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:
+
 
+
PHP-Code:
+
 
+
<pre>
+
$GLOBALS['BE_MOD']['content']['gw_turnierpaare'] = array
+
(
+
    'tables' => array('tl_gw_turnierpaare','tl_gw_meldungen'),
+
    'icon'  => 'system/modules/gw_turnierpaare/icons/turnierpaare.png'
+
); 
+
</pre>
+
 
+
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 "icons" angelegt und mein Icon dort hochgeladen. Im Backend-Modul soll der Berechtigte (also
+
der Sportwart) die Daten Anlegen/Löschen/Ändern dürfen.
+
 
+
Ich speichere die Datei zunächst, und lade meine Backend-Ansicht (als Administrator!) neu. Nun sehe ich in der linken Spalte unter "Inhalte" 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.
+
 
+
[[Datei:Attachment_001.png]]
+
==SQL-Tabellenstruktur anlegen==
+
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 "Parent ID" ist. Meine Turnierpaare haben keinen parent, darum lösche ich die Definition von ''pid'' und die Festlegung von ''pid'' als Key.
+
 
+
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:
+
 
+
Code:
+
<pre>
+
CREATE TABLE `tl_gw_turnierpaare` (
+
  `id` int(10) unsigned NOT NULL auto_increment,
+
  `sorting` int(10) unsigned NOT NULL default '0',
+
  `tstamp` int(10) unsigned NOT NULL default '0',
+
  `partnernachname` varchar(64) NOT NULL default '_',
+
  `partnervorname` varchar(64) NULL,
+
  `partnerinnachname` varchar(64) NULL,
+
  `partnerinvorname` varchar(64) NULL,
+
  `startgruppe` varchar(32) NOT NULL default '_',
+
  `startklasselatein` varchar(12) NULL,
+
  `startklassestandard` varchar(12) NULL,
+
  `aktiv` int(1) NOT NULL default '0',
+
  `aktivseit` int(4) NULL,
+
  `aktivbis` int(4) NULL,
+
  `password` varchar(32) NULL,
+
  `bild` varchar(255) NULL,
+
  `anschrift` text NULL,
+
  `zeigeanschrift` int(1) NOT NULL default '0',
+
  `telefon` varchar(32) NULL,
+
  `zeigetelefon` int(1) NOT NULL default '0',
+
  `fax` varchar(32) NULL,
+
  `zeigefax` int(1) NOT NULL default '0',
+
  `mobil` varchar(32) NULL,
+
  `zeigemobil` int(1) NOT NULL default '0',
+
  `email` varchar(128) NULL,
+
  `zeigeemail` int(1) NOT NULL default '0',
+
  `homepage` varchar(128) NULL,
+
  `zeigehomepage` int(1) NOT NULL default '0',
+
  `beschreibung` text NULL,
+
  PRIMARY KEY  (`id`),
+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
</pre>
+
Man kann sich hier jetzt beliebige Gedanken über die Datenstruktur, Abstraktion, Normalisierung usw machen. Ich möchte es jetzt '''so''' lösen.
+
 
+
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:
+
 
+
Code:
+
 
+
<pre>
+
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 '1900-01-01',
+
  `startgruppe` varchar(32) NOT NULL default '_',
+
  `startklasse` varchar(12) NOT NULL default '_',
+
  `lat_std` char(1) NOT NULL default '_',
+
  `turnierort` varchar(128) NOT NULL default '_',
+
  `turnierart` varchar(64) NULL,
+
  `anzahlpaare` int(4) NULL,
+
  `platz_von` int(4) NULL,
+
  `platz_bis` int(4) NULL,
+
  `bemerkung` text NULL,
+
  PRIMARY KEY  (`id`),
+
  KEY `pid` (`pid`)
+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
</pre>
+
 
+
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.
+
 
+
[[Datei:Attachment_002.png]]
+
 
+
Was dann kommt, erstaunt mich dann aber doch etwas: Die Datenbankstruktur soll weiterhin nicht aktuell sein:
+
 
+
[[Datei:attachment_003.png]]
+
 
+
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 "passiert".
+
 
+
Meine Frage an dieser Stelle also an die erfahrenen Entwickler: Was ist an meiner SQL-Definition "falsch", dass die Tabellen zwar richtig angelegt werden, das TYPOlight-Install-Tool aber damit nicht zurecht kommt?
+
===Diskussionsbeiträge aus dem Forum===
+
{{Hinweis| Diskussionsbeiträge aus dem Forum einarbeiten!}}
+
==SQL reloaded==
+
Nach kleinem Kampf mit dem Install-Tool sieht das SQL für meine beiden Tabellen in database.sql nun so aus:
+
 
+
Code:
+
 
+
<pre>
+
CREATE TABLE `tl_gw_turnierpaare` (
+
  `id` int(10) unsigned NOT NULL auto_increment,
+
  `sorting` int(10) unsigned NOT NULL default '0',
+
  `tstamp` int(10) unsigned NOT NULL default '0',
+
  `partnernachname` varchar(64) NOT NULL default '',
+
  `partnervorname` varchar(64) NULL default NULL,
+
  `partnerinnachname` varchar(64) NULL default NULL,
+
  `partnerinvorname` varchar(64) NULL default NULL,
+
  `startgruppe` varchar(32) NOT NULL default '',
+
  `startklasselatein` varchar(12) NULL default NULL,
+
  `startklassestandard` varchar(12) NULL default NULL,
+
  `aktiv` int(1) NOT NULL default '0',
+
  `aktivseit` int(4) NULL default NULL,
+
  `aktivbis` int(4) NULL default NULL,
+
  `password` varchar(32) NULL default NULL,
+
  `bild` varchar(255) NULL default NULL,
+
  `anschrift` text NULL,
+
  `zeigeanschrift` int(1) NOT NULL default '0',
+
  `telefon` varchar(32) NULL default NULL,
+
  `zeigetelefon` int(1) NOT NULL default '0',
+
  `fax` varchar(32) NULL default NULL,
+
  `zeigefax` int(1) NOT NULL default '0',
+
  `mobil` varchar(32) NULL default NULL,
+
  `zeigemobil` int(1) NOT NULL default '0',
+
  `email` varchar(128) NULL default NULL,
+
  `zeigeemail` int(1) NOT NULL default '0',
+
  `homepage` varchar(128) NULL default NULL,
+
  `zeigehomepage` int(1) NOT NULL default '0',
+
  `beschreibung` text NULL,
+
  PRIMARY KEY  (`id`),
+
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
 
+
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 '1900-01-01',
+
  `startgruppe` varchar(32) NOT NULL default '',
+
  `startklasse` varchar(12) NOT NULL default '',
+
  `lat_std` char(1) 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;
+
</pre>
+
 
+
und wir merken uns:
+
 
+
* NOT NULL-Felder mit default (logisch)
+
 
+
* NULL-"text"-Felder OHNE default
+
 
+
* Sonstige NULL-Felder mit "default NULL"
+
 
+
* default _KLEIN_ schreiben
+
 
+
* Und falls man da was verändert: _2_ Leerzeichen zwischen PRIMARY KEY und (`id`)
+
 
+
Und hier nochmal der Link zum Thread, der das erklärt: [http://www.typolight-community.de/showthread.php?t=41. contao-community-forum]
+
 
+
So, das Install-Tool ist zufrieden, die Datenbank-Tabellen angelegt - es kann weiter gehen!
+
 
+
=Wir wagen uns in das DCA-Land=
+
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 "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.
+
 
+
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.
+
 
+
PHP-Code:
+
 
+
<pre>
+
$GLOBALS['TL_DCA']['tl_gw_turnierpaare'] = array
+
(
+
    // Config
+
    'config' => array
+
    (
+
        'dataContainer'              => 'Table',
+
        'enableVersioning'            => true
+
    ),
+
... 
+
</pre>
+
 
+
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 "child Table" angeben kann. Da die Turniermeldungen Childs der Turnierpaare werden soll, ergänze ich also
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'ctable'                      => 'tl_gw_meldungen' 
+
</pre>
+
 
+
Die verbleibenden Optionen in ''config'' erscheinen mir nicht weiter von Bedeutung. Weiter geht es mit dem Abschnitt ''list'', und dort mit ''sorting'':
+
 
+
PHP-Code:
+
 
+
<pre>
+
    // List
+
    'list' => array
+
    (
+
        'sorting' => array
+
        (
+
            'mode'                    => 1,
+
            'fields'                  => array(''),
+
            'flag'                    => 1
+
        ), 
+
</pre>
+
 
+
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:
+
 
+
PHP-Code:
+
 
+
<pre>
+
            'fields'                  => array('partnernachname','partnerinnachname'), 
+
</pre>
+
 
+
Als nächstes kommt ein Block ''label'':
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'label' => array
+
        (
+
            'fields'                  => array(''),
+
            'format'                  => '%s'
+
        ), 
+
</pre>
+
 
+
Hier scheint es wohl darum zu gehen, was in der Liste der schon bestehenden Tabelleneinträge eingezeigt wird. Ich verändere die Zeilen auf
+
 
+
PHP-Code:
+
 
+
<pre>
+
            'fields'                  => array('partnernachname','partnervorname','partnerinnachname','partnerinvorname','startgruppe','startklassestd','startklasselat'),
+
            'format'                  => '%s, %s und %s, %s - %s %s LAT / %s STD' 
+
</pre>
+
 
+
Etwas "domain-specific knowledge": Startgruppe ist im Prinzip die Altersklasse, Startklasse ist die Leistungsklasse (Die "Liga"), 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 "''%s''" 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:
+
 
+
PHP-Code:
+
 
+
<pre>
+
        '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_turnierpaare']['edit'],
+
                'href'                => 'act=edit',
+
                'icon'                => 'edit.gif'
+
            ),
+
            'copy' => array
+
            (
+
                'label'              => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['copy'],
+
                'href'                => 'act=copy',
+
                'icon'                => 'copy.gif'
+
            ),
+
            'delete' => array
+
            (
+
                'label'              => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['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_turnierpaare']['show'],
+
                'href'                => 'act=show',
+
                'icon'                => 'show.gif'
+
            )
+
        )
+
    ), 
+
</pre>
+
 
+
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.
+
 
+
PHP-Code:
+
 
+
<pre>
+
    // Palettes
+
    'palettes' => array
+
    (
+
        '__selector__'                => array(''),
+
        'default'                    => ''
+
    ),
+
    // Subpalettes
+
    'subpalettes' => array
+
    (
+
        ''                            => ''
+
    ), 
+
</pre>
+
 
+
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.
+
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
+
 
+
PHP-Code:
+
 
+
<pre>
+
    // Palettes
+
    'palettes' => array
+
    (
+
        '__selector__'                => array(''),
+
        'default'                    => 'partnernachname,partnervorname;partnerinnachname,partnerinvorname'
+
    ), 
+
</pre>
+
 
+
''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:
+
 
+
PHP-Code:
+
 
+
<pre>
+
    // Fields
+
    'fields' => array
+
    (
+
        '' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare'][''],
+
            'exclude'                => true,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>true, 'maxlength'=>255
+
)
+
        )
+
    )
+
); 
+
</pre>
+
 
+
Ich halte mich erstmal an das Skelett, und füge nur die Feldnamen hinzu, und vervielfältige den Block auf insgesamt 4 Stück:
+
 
+
PHP-Code:
+
 
+
<pre>
+
    // Fields
+
    'fields' => array
+
    (
+
        'partnernachname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>true, 'maxlength'=>64)
+
        ),
+
        'partnervorname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnervorname'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength'=>64
+
)
+
        ),
+
        'partnerinnachname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinnachname'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength'=>64
+
)
+
        ),
+
        'partnerinvorname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinvorname'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength'=>64
+
)
+
        )
+
    ) 
+
</pre>
+
 
+
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.
+
 
+
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:
+
 
+
[[Datei:Attachment_004.png]]
+
 
+
Und man kann auch schon was eingeben:
+
 
+
[[Datei:Attachment_005.png]]
+
 
+
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.
+
 
+
Im nächsten Post wird das alles erweitert und "poliert". Zur Übersicht nochmal mein aktueller Stand der Datei ''/system/modules/gw_turnierpaare/dca/tl_gw_turnierpaare.php'':
+
 
+
PHP-Code:
+
 
+
<pre>
+
/**
+
* Table tl_gw_turnierpaare 
+
*/
+
$GLOBALS['TL_DCA']['tl_gw_turnierpaare'] = array
+
(
+
    // Config
+
    'config' => array
+
    (
+
        'dataContainer'              => 'Table',
+
        'enableVersioning'            => true,
+
        'ctable'                      => 'tl_gw_meldungen'
+
    ),
+
    // List
+
    'list' => array
+
    (
+
        'sorting' => array
+
        (
+
            'mode'                    => 1,
+
            'fields'                  => array('partnernachname','partnerinnachname'),
+
            'flag'                    => 1
+
        ),
+
        'label' => array
+
        (
+
            'fields'                  => array('partnernachname','partnervorname','partnerinnachname','partnerinvorname','startgruppe','startklassestd','startklasselat'),
+
            'format'                  => '%s, %s und %s, %s - %s %s LAT / %s STD'
+
        ),
+
        '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_turnierpaare']['edit'],
+
                'href'                => 'act=edit',
+
                'icon'                => 'edit.gif'
+
            ),
+
            'copy' => array
+
            (
+
                'label'              => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['copy'],
+
                'href'                => 'act=copy',
+
                'icon'                => 'copy.gif'
+
            ),
+
            'delete' => array
+
            (
+
                'label'              => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['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_turnierpaare']['show'],
+
                'href'                => 'act=show',
+
                'icon'                => 'show.gif'
+
            )
+
        )
+
    ),
+
    // Palettes
+
    'palettes' => array
+
    (
+
        '__selector__'                => array(''),
+
        'default'                    => 'partnernachname,partnervorname;partnerinnachname,partnerinvorname'
+
    ),
+
    // Subpalettes
+
    'subpalettes' => array
+
    (
+
        ''                            => ''
+
    ),
+
    // Fields
+
    'fields' => array
+
    (
+
        'partnernachname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>true, 'maxlength'=>64)
+
        ),
+
        'partnervorname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnervorname'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength'=>64
+
)
+
        ),
+
        'partnerinnachname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinnachname'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength'=>64
+
)
+
        ),
+
        'partnerinvorname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinvorname'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength'=>64
+
)
+
        )
+
    )
+
); 
+
</pre>
+
==Verwirrung im DCA-Land==
+
Nachdem ich einige Testpaare in meine "Minimalmaske" eingetragen habe, stelle ich fest, dass es nicht ganz so aussieht, wie ich es gerne hätte.
+
 
+
[[Datei:Attachment_006.png]]
+
 
+
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 "A", "B", "C", usw...Ich vermute, dass das mit dem Eintrag ''['list']['sorting']['flag']'' zusammenhängt, den ich auf "1" hatte, laut Referenz ''Sort by initial letter ascending'':
+
 
+
PHP-Code:
+
 
+
<pre>
+
    // List
+
    'list' => array
+
    (
+
        'sorting' => array
+
        (
+
            'mode'                    => 1,
+
            'fields'                  => array('partnernachname', 'partnervorname', 'partnerinnachname', 'partnerinvorname'),
+
            'flag'                    => 1
+
        ), 
+
</pre>
+
 
+
Ich spiele also etwas mit ''flag'' herum, und stelle fest: Irgendwie beeinflusst das garnix.
+
* 2 = ''Sort by initial letter descending'',
+
*  3 = ''Sort by initial two letters ascending'',
+
*  4 = ''Sort by initial two letters descending'',
+
* 11 = ''Sort ascending'' oder
+
* 12 = ''Sort descending''
+
machen in meiner Auflistung nirgendwo irgendeinen Unterschied. Immer wird stur ''ascending'' in der Reihenfolge meiner Sortierfelder sortiert, und für jeden "Unique" Herrennachnamen gibt es eine Gruppenüberschrift.
+
+
In meiner Verzweifelung setze ich ''['list']['sorting']['mode']'' auf 0, laut Referenz ''Records are not sorted''. Das Ergebnis sieht so aus
+
 
+
[[Datei:Attachment_007.png]]
+
 
+
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.
+
 
+
Um das Sortieren vielleicht "von Hand" steuern zu können, füge ich streng nach Referenz die Zeile
+
 
+
PHP-Code:
+
 
+
<pre>
+
            'panelLayout'            => 'search,sort,filter' 
+
</pre>
+
 
+
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.
+
 
+
Meine ''['list']['sorting']''-Sektion sieht nun so aus:
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'sorting' => array
+
        (
+
            'mode'                    => 0,
+
            'fields'                  => array('partnernachname', 'partnervorname', 'partnerinnachname', 'partnerinvorname'),
+
            'flag'                    => 1,
+
            'panelLayout'            => 'search,sort,filter'
+
        ), 
+
</pre>
+
 
+
Jemand eine Ahnung, warum das Verhalten so ist, bzw. warum mich die Referenz für die DCA-Records so im Stich lässt?
+
Danke...
+
 
+
==Leichte Entwirrung im DCA-Land==
+
Lösung gefunden! Bei den einzelnen ''field''-Beschreibungen muss noch die Freigabe zum Sortieren, Filtern und Suchen gegeben werden. Das sieht jetzt so aus:
+
 
+
PHP-Code:
+
 
+
<pre>
+
    // Fields
+
    'fields' => array
+
    (
+
        'partnernachname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'search'                  => true,
+
            'sorting'                => true,
+
            'filter'                  => true,
+
            'flag'                    => 1,
+
            'eval'                    => array('mandatory'=>true, 'maxlength'=>64)
+
        ),
+
        'partnervorname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnervorname'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength'=>64
+
)
+
        ),
+
        'partnerinnachname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinnachname'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'search'                  => true,
+
            'sorting'                => true,
+
            'filter'                  => true,
+
            'flag'                    => 1,
+
            'eval'                    => array('mandatory'=>false, 'maxlength'=>64
+
)
+
        ),
+
        'partnerinvorname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnerinvorname'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength'=>64
+
)
+
        )
+
    ) 
+
</pre>
+
 
+
Mit Ergebnis:
+
 
+
[[Datei:Attachment_008.png]]
+
 
+
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...
+
 
+
Ergänzung: Und wenn ich ''['sorting']['mode']'' auf 2 setze, dann kann ich sogar mein Sortierfeld auswählen....sehr schön...
+
 
+
==DCA-Polishing==
+
Nachdem also die leichten Verwirrungen rund um den DCA-Record beseitigt sind, geht es weiter damit, die Backend-"Maske" für die ''tl_gw_turnierpaare''-Tabelle zu definieren und zu "polieren".
+
 
+
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']'':
+
 
+
PHP-Code:
+
 
+
<pre>
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname_explanation'], 
+
</pre>
+
 
+
Der entsprechende Text muss in den Sprachfiles natürlich noch eingetragen werden - später.
+
 
+
Außerdem ergänze ich den ''eval''-Wert meiner bisherigen 4 Eingabefelder um den Wert'' 'minlength' => 1'', um bei den namen eine Mindestlänge zu erzwingen (Beim Wert 1 wahrscheinlich überflüssig, aber egal).
+
 
+
Bei dem Nachnamen des Partners und der Partnerin ergänze ich außerdem '''tl_class' => '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.
+
 
+
Meine Einstellungen für das ''partnernachname''-Feld sehen jetzt so aus:
+
 
+
PHP-Code:
+
 
+
<pre>
+
    // Fields
+
    'fields' => array
+
    (
+
        'partnernachname' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['partnernachname_explanation'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'search'                  => true,
+
            'sorting'                => true,
+
            'filter'                  => true,
+
            'flag'                    => 1,
+
            'eval'                    => array('mandatory'=>true, 'minlength' => 1, 'maxlength'=>64, 'tl_class' => 'w50')
+
        ), 
+
</pre>
+
 
+
Wo ich gerade noch optisch etwas aufräume, baue ich den Eintrag ''default'' unter ''palettes'' so um:
+
 
+
PHP-Code:
+
 
+
<pre>
+
    // Palettes
+
    'palettes' => array
+
    (
+
        '__selector__'                => array(''),
+
        'default'                    => '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname;'
+
    ), 
+
</pre>
+
 
+
''{name_legend}'' legt die Überschrift für die "Palette" 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:
+
 
+
[[Datei:Attachment_009.png]]
+
 
+
Wenn man sich "vernünftige" Überschriften aus dem Sprachfile dazu vorstellt, schon mal ganz OK :-).
+
 
+
Nun geht es um die noch fehlenden Tabellenfelder.
+
 
+
Zunächst kommt ''startgruppe'', das bezeichnet die Altersklasse des Paars. Das Feld soll ''mandatory'' sein, aber auch eine "leere Option" 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:
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'startgruppe' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startgruppe'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startgruppe_explanation'],
+
            'exclude'                => false,
+
            'inputType'              => 'select',
+
            'options'                => array('KIN I','KIN II', 'JUN I', 'JUN II', 'JUG', 'HGR', 'HGR II', 'SEN I', 'SEN II', 'SEN III', 'SEN IV'),
+
            'eval'                    => array('mandatory'=>true, 'includeBlankOption' => true)
+
        ), 
+
</pre>
+
 
+
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.
+
 
+
Dann kommen ''startklasselatein'' und ''startklassestandard''. Inhaltlich kann in beiden Feldern dasselbe drinstehen, darum ist es fast nur Copy&Paste für das zweite Feld. Die Definition sieht so aus:
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'startklasselatein' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklasselatein'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['startklasselatein_explanation'],
+
            'exclude'                => false,
+
            'inputType'              => 'select',
+
            'options'                => array('E','D', 'C', 'B', 'A', 'S', 'PRO', 'LL', 'OL', 'RL', '2. BL', '1. BL'),
+
            'eval'                    => array('mandatory'=>true, 'includeBlankOption' => true, 'tl_class' => 'w50')
+
        ), 
+
</pre>
+
 
+
Auch hier wieder eine Drop-Down-Box mit Optionen und Möglichkeit der "leeren Option". Durch ''tl_class => 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 => w50''!
+
 
+
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.
+
 
+
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.
+
 
+
PHP-Code:
+
 
+
<pre>
+
    // Palettes
+
    'palettes' => array
+
    (
+
        '__selector__'                => array(''),
+
        'default'                    => '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname;
+
{classes_legend},startgruppe,startklasselatein,startklassestandard'
+
    ), 
+
</pre>
+
 
+
Ergebnis:
+
 
+
[[Datei:Attachment_010.png]]
+
 
+
Weiter geht's, jetzt folgen die Felder ''aktiv'', ''aktivseit'' und ''aktivbis''.
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'aktiv' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktiv'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktiv_explanation'],
+
            'exclude'                => false,
+
            'inputType'              => 'checkbox',
+
            'eval'                    => array('mandatory'=>true, 'isBoolean' => true)
+
        ), 
+
</pre>
+
 
+
''Aktiv'' wird eine Checkbox. Ich weiß zwar nicht, was es für eine Bedeutung hat, aber da eine CheckBox immer "Boolean" ist, setze ich in ''eval'' ''isBoolean => true''.
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'aktivseit' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivseit'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivseit_explanation'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'minlength' => 4, 'maxlength' => 4, 'rgxp' => 'digit', 'tl_class' => 'w50')
+
        ),
+
        'aktivbis' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivbis'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['aktivbis_explanation'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'minlength' => 4, 'maxlength' => 4, 'rgxp' => 'digit')
+
        ), 
+
</pre>
+
 
+
''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 "1900" anfangen, wenn man nach "2004" will, ist auch kein Vergnügen. Das erste Feld setze ich mit ''tl_class => w50'' nach links, um das zweite Feld daneben darstellen zu können.
+
 
+
Ich ergänze die Paletten-Definition um
+
 
+
PHP-Code:
+
 
+
<pre>
+
{aktiv_legend:hide},aktiv,aktivseit,aktivbis; 
+
</pre>
+
 
+
Da die Felder nicht so oft editiert werden, schließe ich die Palette defaultmäßig.
+
 
+
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.
+
 
+
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:
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'password' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['password'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['password_explanation'],
+
            'exclude'                => false,
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'minlength' => 1, 'maxlength' => 64)
+
        ) 
+
</pre>
+
 
+
Dieses Feld soll (alleine) in einer eigenen Palette stehen, darum ergänze ich die Palettendefinition um:
+
 
+
PHP-Code:
+
 
+
<pre>
+
{password_legend:hide},password; 
+
</pre>
+
 
+
Zwischenstand der Backend-Maske:
+
 
+
[[Datei:Attachment_011.png]]
+
 
+
Und nochmal die gesamte Paletten-Definition:
+
 
+
PHP-Code:
+
 
+
<pre>
+
    // Palettes
+
    'palettes' => array
+
    (
+
        '__selector__'                => array(''),
+
        'default'                    => '{name_legend},partnernachname,partnervorname,partnerinnachname,partnerinvorname;
+
{classes_legend},startgruppe,startklasselatein,startklassestandard;{aktiv_legend:hide},aktiv,aktivseit,aktivbis;{password_legend:hide},password;'
+
    ), 
+
</pre>
+
 
+
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.
+
 
+
== Ein Bug, ein Bug!==
+
Nachdem man jetzt Startklassen eingeben, entdecke ich natürlich gleich einen Bug, und zwar in ''['list']['label']['fields']''.
+
 
+
VORHER (falsch):
+
 
+
PHP-Code:
+
 
+
<pre>
+
            'fields'                  => array('partnernachname','partnervorname','partnerinnachname','partnerinvorname','startgruppe','startklassestd','startklasselat'), 
+
</pre>
+
 
+
NACHHER (richtig):
+
 
+
PHP-Code:
+
 
+
<pre>
+
            'fields'                  => array('partnernachname','partnervorname','partnerinnachname','partnerinvorname','startgruppe','startklassestandard','startklasselatein'), 
+
</pre>
+
 
+
D.h. die beiden Felder für die Startklasse Standard und Latein waren falsch benannt. Sorry.
+
 
+
Und weiter geht es mit Bugs:
+
Wenn ich bei Feldern, die eine "leere Option" zulassen, trotzdem in '''eval' mandatory => true'' fordere, kann die leere Option nicht ausgewählt werden. Gut, irgendwie auch logisch. Aus diesem Grund setze ich bei ''startgruppe'', ''startklasselatein'' und ''startklassestandard'' "'''mandatory' => false''", um auch die leere Option zuzulassen.
+
 
+
Und letzter kleiner Fehler:
+
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:
+
 
+
PHP-Code:
+
 
+
<pre>
+
            'format'                  => '%s, %s und %s, %s - %s %s STD / %s LAT' 
+
</pre>
+
==Nochmals anders==
+
Tjaja, wie das bei so einem Tagebuch im Gegensatz zum "durchgeplanten und polierten" Tutorial so ist: Ich habe mir nochmal was anders überlegt.
+
 
+
Ich habe mich entschlossen, die Felder ''startklasselatein'' und ''startklassestandard'' doch ''mandatory'' zu machen, aber als Option eine Leer-Option "-" 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 "LAT" noch ein Strich steht, statt einfach garnichts.
+
 
+
Bei beiden Feldern sieht der Eintrag in ''['fields']'' jetzt also so aus:
+
 
+
PHP-Code:
+
 
+
<pre>
+
            'options'                => array('-', 'E','D', 'C', 'B', 'A', 'S', 'PRO', 'LL', 'OL', 'RL', '2. BL', '1. BL'),
+
            'eval'                    => array('mandatory'=>true) 
+
</pre>
+
 
+
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:
+
 
+
PHP-Code:
+
 
+
<pre>
+
            'eval'                    => array('mandatory'=>false, 'isBoolean' => true) 
+
</pre>
+
 
+
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.
+
 
+
''['list']['label']['format']'' lautet jetzt:
+
 
+
PHP-Code:
+
 
+
<pre>
+
            'format'                  => '<span style="font-weight: bold;">%s</span>, %s und <span style="font-weight: bold;">%s</span>, %s - <span style="font-weight: bold; margin-left: 5px">%s <span style="color: orange; margin-left: 5px;">%s STD</span> / <span style="color: red;">%s LAT</span></span>' 
+
</pre>
+
 
+
Und sieht so aus:
+
 
+
[[Datei:Attachment_012.png]]
+
 
+
Aber im nächsten Post geht es endlich mit den restlichen Feldern der ''tl_gw_turnierpaare''-Tabelle weiter.
+
==DCA - Almost there==
+
Schritt 4 scheint kein Ende zu nehmen. Wie erwartet erweist sich das Thema "DCA" als harter Brocken.
+
 
+
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
+
 
+
Statt die Anschrift in Straße, PLZ, Ort, usw. aufzusplitten, habe ich hierfür eine ''textarea'' vorgesehen. Im DCA sieht das so aus:
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'anschrift' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['anschrift'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['anschrift_explanation'],
+
            'inputType'              => 'textarea',
+
            'eval'                    => array('mandatory'=>false, 'cols' => 40, 'rows' => 5)
+
        ), 
+
</pre>
+
 
+
Alles wie gehabt, zusätzlich geben ''cols'' und ''rows'' die Spalten und Zeilen des Eingabebereichs an.
+
 
+
Die Definition für das Flag, ob die Anschrift öffentlich angezeigt werden soll, ist so wie beim Feld ''aktiv'':
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'zeigeanschrift' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeanschrift'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeanschrift_explanation'],
+
            'inputType'              => 'checkbox',
+
            'eval'                    => array('mandatory'=>false, 'isBoolean' => true)
+
        ), 
+
</pre>
+
 
+
Nicht Besonderes!
+
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 "Anzeigen"-Checkbox:
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'telefon' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['telefon'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['telefon_explanation'],
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength' => 32, 'rgxp' => 'phone')
+
        ),
+
        'zeigetelefon' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigetelefon'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigetelefon_explanation'],
+
            'inputType'              => 'checkbox',
+
            'eval'                    => array('mandatory'=>false, 'isBoolean' => true, 'tl_class' => 'clr m12 w50')
+
        ),
+
        'fax' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['fax'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['fax_explanation'],
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength' => 32, 'rgxp' => 'phone')
+
        ),
+
        'zeigefax' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigefax'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigefax_explanation'],
+
            'inputType'              => 'checkbox',
+
            'eval'                    => array('mandatory'=>false, 'isBoolean' => true, 'tl_class' => 'clr m12 w50')
+
        ),
+
        'mobil' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['mobil'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['mobil_explanation'],
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength' => 32, 'rgxp' => 'phone')
+
        ),
+
        'zeigemobil' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigemobil'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigemobil_explanation'],
+
            'inputType'              => 'checkbox',
+
            'eval'                    => array('mandatory'=>false, 'isBoolean' => true, 'tl_class' => 'clr m12 w50')
+
        ),
+
        'email' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['email'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['email_explanation'],
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength' => 32, 'rgxp' => 'email')
+
        ),
+
        'zeigeemail' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeemail'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigeemail_explanation'],
+
            'inputType'              => 'checkbox',
+
            'eval'                    => array('mandatory'=>false, 'isBoolean' => true, 'tl_class' => 'clr m12 w50')
+
        ),
+
        'homepage' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['homepage'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['homepage_explanation'],
+
            'inputType'              => 'text',
+
            'eval'                    => array('mandatory'=>false, 'maxlength' => 32, 'rgxp' => 'url')
+
        ),
+
        'zeigehomepage' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigehomepage'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['zeigehomepage_explanation'],
+
            'inputType'              => 'checkbox',
+
            'eval'                    => array('mandatory'=>false, 'isBoolean' => true, 'tl_class' => 'clr m12 w50')
+
        ), 
+
</pre>
+
 
+
Die ''tl_class''-Werte sind so gewählt, dass jede "Anzeigen"-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 "zerschossen" aus.
+
 
+
Den Wert ''['palettes']['default']'' ergänze ich noch um
+
 
+
PHP-Code:
+
 
+
<pre>
+
'{contact_legend:hide},zeigeanschrift,anschrift,zeigetelefon,telefon,zeigefax,fax,zeigemobil,mobil,zeigeemail,email,zeigehomepage,homepage;' 
+
</pre>
+
 
+
Ergebnis:
+
 
+
[[Datei:Attachment_013.png]]
+
 
+
''Beschreibung'' ist eine Textarea, die in eigener Palette angezeigt werden soll. Einzige Besonderheit ist hier, dass ich HTML im Inhalt zulassen will.
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'beschreibung' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['beschreibung'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['beschreibung_explanation'],
+
            'inputType'              => 'textarea',
+
            'eval'                    => array('mandatory'=>false, 'cols' => 80, 'rows' => 20, 'allowHtml' => true)
+
        ), 
+
</pre>
+
 
+
Schließlich fehlt noch das Bild. Hier wollte ich eine Bilder-Auswahl wie im Content-Element "Bild" haben. Ich habe eine Weile herumexperimentiert, insbesondere mit dem Feldtyp "radioTable" (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:
+
 
+
PHP-Code:
+
 
+
<pre>
+
        'bild' => array
+
        (
+
            'label'                  => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['bild'],
+
            'explanation'            => &$GLOBALS['TL_LANG']['tl_gw_turnierpaare']['bild_explanation'],
+
            'inputType'              => 'fileTree',
+
            'eval'                    => array('mandatory'=>false, 'files'=>true, 'fieldType'=>'radio', 'filesOnly' => true, 'extensions' => 'jpg,jpeg,png,gif', 'path' => 'tl_files/GW/Bilder_Turnierpaare/')
+
        ) 
+
</pre>
+
 
+
Typ ist also ein ''fileTree'', in dem man mittels Radiobutton EIN File auswählen kann (''fieldType => radio''), in dem Dateien mit den Erweiterungen jpeg,jpg,png und gif angezeigt werden (''extensions''), in dem Unterverzeichnisse UND Dateien angezeigt werden (''files => true'', sonst werden NUR Verzeichnisse angezeigt), und in dem man mittels des Radiobuttons auch ausschließlich Dateien auswählen kann, KEINE Unterverzeichnisse (''filesOnly => true''). Zusätzlich gebe ich den "Basis-Pfad" 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.
+
 
+
Noch die Palettendefinition erweitern um
+
 
+
PHP-Code:
+
 
+
<pre>
+
'{beschreibung_legend:hide},beschreibung;{bild_legend:hide},bild;' 
+
</pre>
+
 
+
und wir landen hier:
+
 
+
[[Datei:Attachment_014.png]]
+
 
+
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 :-).
+
 
+
Folgende "Probleme" habe ich noch: Meine Palettendefinition sieht insgesamt so aus:
+
 
+
PHP-Code:
+
 
+
<pre>
+
    // Palettes
+
    'palettes' => array
+
    (
+
        '__selector__'                => array(''),
+
        'default'                    => '{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;'
+
    ), 
+
</pre>
+
 
+
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?
+
 
+
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 => 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).
+
 
+
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.
+
 
+
Mein "Traum" 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.
+
 
+
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.
+
 
+
=Language Files=
+
 
+
[[Datei:Attachment_015.png]]
+
 
+
=Von Callbacks und Subpaletten=
+
 
+
[[Datei:Attachment_016.png]]
+
 
+
[[Datei:Attachment_017.png]]
+
 
+
=Endlich Frontend!=
+
==Ein wenig Finetuning==
+
=Parameter fürs Modul=
+
==Parameter fürs Modul, die Zweite==
+
=Details, Details, Details=
+
=Etwas Feinschliff=
+
=Die zweite Tabelle=
+
=Callback-Magie=
+
=Frontendmodul Meldeliste=
+
==JOIN-Power==
+
=Downloads=
+
dl1ely hat eine gezippte Version seiner Extension zum Download zur Verfügung gestellt, der Stand ist vom 29.05.2010.
+
Diese Datei entpacken Sie bitte in den TL/contao-Ordner ''/system/modules/''.
+
 
+
[http://dl.dropbox.com/u/804662/gw_turnierpaare_20100529.zip Quelltext des Moduls]
+
 
+
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 ("Ich finde dein Tutorial gaaaaaanz toll!") wurden entfernt. Trotzdem hat die Datei eine Größe von ca. 1,5 MB und umfasst ca. 125 Seiten!
+
 
+
[[http://de.contaowiki.org/images/de/d/d2/Tagebuch_einer_Extension-Entwicklung_-_bis_104.pdf PDF-Datei mit Forumsbeiträgen]]
+

Aktuelle Version vom 9. Juli 2010, 23:24 Uhr

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

Bitte erweitere ihn und entferne erst anschliessend diesen Hinweis.

Tagebuch einer Extension-Entwicklung / Vorbemerkungen der Wiki-Autoren

betrifft
TYPOlight Version ab TL 2.8
Extensions Extension Creator


Vorbemerkungen

  • Die Artikel nehmen einen sehr ausführlichen Forumsthread aus dem Contao-Community-Forum Allgemeine Infos für Third-Party Extensions -> Entwickler-Tutorials auf, der unter dem Titel Tagebuch einer Extension-Entwicklung von dl1ely (Stefan) verfasst wurde.
  • Sie finden den Thread hier: [Original Forumsbeitrag]. Dort können Sie die Diskussion weiterführen. Ob künftige Forumsbeiträge hier eingearbeitet werden, ist nicht sichergestellt.
  • Die Originalbeiträge wurden redaktionell leicht überarbeitet. Dabei wurden neben forumspezifischen Besonderheiten auch Überleitungen, Anrede- und Grußformeln, Bewertungen ("Ich finde das Tutorial gaaaanz toll!") u.ä. entfernt.
  • An einigen Stellen wurden kleine Ergänzungen eingefügt.
  • Entgegen den Wiki-Gepflogenheiten sind die Artikel in der Ich-Form gehalten, da es sich um einen Erfahrungsbericht handelt.
  • 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.


Und so ist das Tutorial aufgebaut:

  • TEE-00 Vorbemerkungen
Ansichten
Meine Werkzeuge

Contao Community Documentation

irgendwie ist das Leben nicht fair...ich mache eine Webseite über Toilettenreinigung und Martin stellt Fotos für eine Schönheitswebseite frei...

Leo Unglaub
Navigation
Verstehen
Verwenden
Entwickeln
Verschiedenes
Werkzeuge