TEE-01 Einleitung

Aus Contao Community Documentation

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

Bitte erweitere ihn und entferne erst anschliessend diesen Hinweis.

Tagebuch einer Extension-Entwicklung

betrifft
TYPOlight Version ab TL 2.8
Extensions Extension Creator


Allgemeine Hinweise

Ich möchte hier gerne eine Art "Tagebuch" einer Extension-Entwicklung schreiben. 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 zu lernen.

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.

Was bringe ich mit?

Trotzdem ist mir weiterhin nicht glasklar, welche Schritte man bis zur eigenen Extension gehen muss.

Vorneweg:

TL = TYPOlight FE = Frontend (Seite, die jeder Surfer sieht) BE = Backend (Seite, die nur eingeloggte "Redakteure" sehen unter der /typolight URL)

Ich verwende folgende Tools:

  • WinSCP unter Windows 7 und
  • PSPad als Editor.

Siehe dazu auch TEE-15 Werkzeuge.

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 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.

Anforderungen und Randbedingungen

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, erst mal 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:

Der Verein besitzt eine Menge an Tanzturnierpaaren. Zu diesen Turnierpaaren gehören Daten wie Name(n), Start- und Altersklassen, und ein Flag, ob das Paar 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.

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 mit tanzen (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
  • Modul Ehemalige Turnierpaare

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.

  • Modul Meldeliste - Eine chronologisch absteigend sortierte Liste aller Melde-Einträge, Neueste also zuerst.
  • Module/Formulare für Änderung der Paardaten im Frontend und zum Hinzufügen von Platzierung/Kommentar bei Meldungen

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.

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.

Coming up next: Extension-"Skelett" 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 :-).


Diskussion im Forum

user: deerwood

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:

Code:

+-------------+ 1    N +--------+        +-----------+        +-----------+
|             |-------<|        |        |           |        |           |
|             |  Mann  |        | 1    N |           | N    1 |           |
|  tl_member  |        |  Paar  |-------<|  Meldung  |>-------|  Turnier  |
|             |  Frau  |        |        |           |        |           |
|             |-------<|        |        |           |        |           |
+-------------+ 1    N +--------+        +-----------+        +-----------+

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.

Eventuell könnte man diese Erweiterung auch generalisieren: statt "Paar" etwa "Mannschaft/Gruppe" 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 "Mannschaft/Gruppe". Besonderheiten wie "Anmeldung normalerweise nur durch den Sportwart" 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.

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.

Nochmals etwas weiter gedacht:

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?

Und was sind denn Turniere/Veranstaltungen? Das sind doch "Events" (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.

Was fehlt also noch? Eigentlich nur die "Mitte" (Meldung) zwischen member_group und calendar_event.

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 "Meldung/Teilnahme").

Bin ich abgeflogen, oder versteht jemand diesen Ansatz oder bin ich einfach dumm und alle machen das bereits so?

user: dl1ely

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 "Lehrbuchbeispiel" einer Extension wäre das wohl genau der richtige Weg.

Folgende Gründe (Die alle nicht "zwingend" sind, aber die Summe macht es) machen es aber für mich unattraktiv:

  • 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.
  • Handling der "Personen" 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.

Die "Alten" 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 "Paar"-Datensatz zwei Datensätze für die tl_member-Tabelle erstellen, und mir dabei größtenteils die Inhalte der Datenfelder (email, passwort, whatever) ausdenken.

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.

  • 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.
  • Vorschlag der Generalisierung: Sicherlich erstrebenswert, aber ich sehe die Gefahr, mich vor lauter Generalisierung "zu verzetteln", und 90% meiner Arbeit in "what-ifs" zu stecken, die in meinem Fall gar nicht benötigt werden.

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 "never-ending Project" daraus machen, an dem ich mich verhebe. Schließlich ist das meine allererste Extension.

Vielleicht wird eine v2 daraus, die dann Anspruch hat, eine allgemeine "Sport-Mannschaften-Turnierwesen"-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.

Im Endeffekt will ich in meinem Tutorial zeigen, wie man Informationen mit Vater-Kind-Beziehungen ablegt, im BE editierbar macht, und in verschiedenen "Views" im Frontend anzeigt. Meine "Spezialsauerei" 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 "Bericht" her ganz raus lassen. Dann wird es nur eine Art "extended version" des CD-Collection-Tutorials, was schon fast in meine Richtung geht, was mir nur zu_ Hoppla-Hopp durch alle Schritte durchgeht.

  • 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.

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 "Einloggen" in die Seite wäre für manche Anwender wahrscheinlich schon zu viel der Veränderung :-). Außerdem schürt so etwas bei Nicht-Turnierpaaren das Gefühl, dass es für eingeloggte Personen "Geheimseiten" gibt, die ihnen nicht zur Verfügung stehen. In diesem Fall wäre das ja auch so, wäre aber nicht transparent.

Wenn jeder Benutzer die Formularseite "Turnierergebnis für Paar XY eintragen, aber nur wenn man das Paarpasswort kennt" sieht, wird das viel weniger Fragen aufwerfen, als wenn es auf einmal "Login-Möglichkeiten" im FE geben wird, die es bisher nicht gab. Das hat immer den Geruch von Privilegisierung, die bei den "Nicht-Privilegierten" auf Ablehnung stößt.

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.

  • 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.

Jede Normalisierung über die Beziehung "Turnierpaar<- 1:N ->Meldung" 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 "clean-Design"-Grundsätzen bei der Konzeption der Struktur der Datenbanktabellen möglichst nah an der etablierten Form bleiben.

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...

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 ungern ein Frontend-Login einführen (müssen).

  • 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!

user: FloB

Zitat von dl1ely
 
Handling der "Personen" 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. [...] 
Die "Alten" 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 "Paar"-Datensatz zwei Datensätze für die tl_member-Tabelle erstellen, und  
mir dabei größtenteils die Inhalte der Datenfelder (email, passwort, whatever) ausdenken.

Nun, aus was bestehen denn die bestehenden Daten? Name, Geburtsdatum ist klar, dann noch Tanzpartner (am besten UserID - oder "Gruppen-ID", 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.

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.

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 "Verwalter-ID" 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).

user: dl1ely

Hehe, ihr blast das Ding schon viel zu weit auf...Trainer-ID o.ä. ist nicht notwendig, Trainer spielen in diesem "Prozess" 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 "TL-Profi". Aber das bin ich noch nicht ;-).

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.

Ansichten
Meine Werkzeuge

Contao Community Documentation

<user> Composer meckert bei Isotope, dass er mit tablelookupwizard 3.1 nicht zurecht kommt - korrekt?
<Toflar> keine Ahnung, sowas weiss ich doch nicht auswendig :D
<user> wer dann ;)
<Toflar> na niemand, deswegen schreibt man's ja in die composer.json

Navigation
Verstehen
Verwenden
Entwickeln
Verschiedenes
Werkzeuge