HSWO_BSC_BACHELORS_THESIS/chapters/konzeption-entwicklung.tex

424 lines
30 KiB
TeX
Raw Normal View History

2023-03-02 02:04:33 +01:00
\chapter{Umsetzung}
\label{chap:umsetzung}
Infolge der Anforderungsanalyse befasst sich das Kapitel \enquote{Umsetzung} mit der Implementation der Anforderungen in dem
Brown-Field Projekt \cite{bib:schwarzer-vorlesung-swa} in Form einer TYPO3-Extension.
\section{Setup einer TYPO3-Extension}
2023-03-21 17:52:19 +01:00
TYPO3-Extensions werden via Composer installiert \cite{bib:typo3-docs-managing-extensions}.
Um eine TYPO3-Extension zu erstellen, muss also ein Composer-Paket erstellt werden.
Um vermeidbare Komplexität zu verhindern, wird das Composer-Paket, welches die hier betrachtete
2023-03-02 02:04:33 +01:00
TYPO3-Extension darstellt, lokal in den versionierten Ordner \enquote{packages} gelegt.
Dieses Verzeichnis wird als Quelle für Composer-Pakete in der
Haupt-composer.json-Datei hinterlegt.
Somit wird ein Composer-Paket nur für dieses Projekt bereitgestellt,
2023-03-21 17:52:19 +01:00
ohne den Aufwand zu haben, der üblicherweise mit dem Bereitstellen eines Paketes einhergeht.
2023-03-02 02:04:33 +01:00
\\
\\
2023-03-21 17:52:19 +01:00
Um das grundlegende Setup einer Extension effizient durchzuführen, wurde eine
existierende Extension mit vergleichbarem Funktionsumfang kopiert, umbenannt und eingefügt.
Spezifisch ist der \enquote{vergleichbare Funktionsumfang}, dass es Datenmodelle und hochpersonalisierte
Frontendlogik in Bezug auf die zuvor genannten Datenmodelle gibt.
2023-03-02 02:04:33 +01:00
\section{Digitization}
Die Phase der Digitazion nach Verhoef et al. befasst sich mit der digitalen Abbildung von Objekten der realen Welt
in einer Art und Weise, sodass diese elektronisch weiterverarbeitet werden können \cite{bib:verhoef, bib:dougherty, bib:loebbecke}.
2023-03-21 17:52:19 +01:00
Das bedeutet, dass in dieser Phase Datenobjekte definiert und implementiert werden.
2023-03-02 02:04:33 +01:00
Ein Datenobjekt besteht nach firmeninternen Konventionen aus zumindest
vier Komponenten:
\begin{description}
\item{Datenbanktabelle} \\
Die Datenbanktabelle persistiert Informationen.
\item{Domain Model} \\
Das Domain Model (auch Model genannt) ist eine PHP-Klasse,
die jeweils die Daten einer Zeile der Datenbanktabelle abbildet.
\item{Repository} \\
Ein Repository ist eine PHP-Klasse, die die Schnittstelle
zwischen der Datenbank und der Model-Klasse darstellt.
\item{\ac{TCA}} \\
Der \ac{TCA} des Modells definiert, wie diese Objekte im TYPO3-Backend dargestellt werden
und bearbeitbar sind.
\end{description}
\cite{bib:typo3-docs-extbase-reference}.
2023-03-21 17:52:19 +01:00
Im Folgenden wurde ein semiformales Diagramm der Objekte und ihren Relationen
angefertigt und in Rücksprache mit dem \ac{PO} finalisiert.
2023-03-02 02:04:33 +01:00
\begin{nicepic}
\includegraphics[width=1\textwidth]{images/objektrelationen-weinlandmosel-einlieferungswerkzeug.png}
\captionof{figure}{Objektrelationen}
\caption*{Quelle: Eigene Darstellung}
\label{fig:objektrelationen}
\end{nicepic}
Nachdem in Erfahrung gebracht wurde, welche konkreten Datenobjekte benötigt werden,
wurden Attribute dieser Objekte dem Pflichtenheft entnommen. Diese wurden in einem
formalen Klassendiagramm festgehalten und in Rücksprache mit dem \ac{PO}
weiter bis zu festen Datentypen und Auswahlmöglichkeiten konkretisiert.
Beispielsweise, dass Wettbewerbskategorien durch TYPO3-Categories repräsentiert werden sollen.
Das hat den Vorteil, dass TYPO3-Categories bereits native Bestandteile eines TYPO3-Redaktionssystemes sind
2023-03-21 17:52:19 +01:00
und alle relevanten Attribute anbieten. Diese sind ein Titel,
eine Parentkategorie und eine Beschreibung.
Das Parent-Attribut ist benötigt, da $n$ dieser Attribute einen Attributbaum bilden
\cite{bib:typo3-docs-sys-category}.
2023-03-21 17:52:19 +01:00
Somit ist es möglich, Unterkategorien zu erstellen. Beispiele hierfür sind die
Unterkategorien \enquote{Trockener Riesling} und \enquote{Halbtrockener Riesling} für die Überkategorie
\enquote{Riesling}.
Rebsorten, Geschmack, Weineigenschaften und Qualität sollen eigene Datentypen
anstatt einfacher Zeichenfolgen sein.
2023-03-24 17:32:59 +01:00
Ziel dessen ist, dass sich Nutzer für einen vorgefertigten, nominalen Eintrag in einem Dropdown-Menü
entscheiden müssen und diese Auswahlmöglichkeiten immer noch im TYPO3-Backend pflegbar sind.
Weinlagen sind im Brown-Field-Projekt bereits vorhanden, also sollen hierfür existierenden Daten
eingebunden werden.
2023-03-24 17:32:59 +01:00
Je Wein sollen beliebig viele Weineigenschaften auswählbar sein, Wettbewerbskategorien,
Geschmacksrichtung, etc, jeweils nur ein Element.
Weitere Notizen zu diesem Gespräch sind im Anhang unter \fullref{chap:anhang-notizen-digitization}
2023-03-02 02:04:33 +01:00
zu finden.
\\
\\
2023-03-24 17:32:59 +01:00
Da das Klassendiagramm nicht auf eine Textseite passt,
2023-03-02 02:04:33 +01:00
befindet es sich vollseitig im Anhang unter \fullref{chap:anhang-class-diagram}.
Die weitere Implementation der Datenobjekte ist unkompliziert und besteht hauptsächlich aus
repetitivem Schreiben von SQL-Tabellen, Domain-Model-Klassen und \acp{TCA}.
2023-03-24 17:32:59 +01:00
Um $m,n$-Beziehungen, wie beispielsweise der Menge der für eine Probe zugelassenen Kategorien
\enquote{allowedCategories}, zwischen $m$ \enquote{Jahresauswahlprobe}-Objekten und
$n$ \enquote{Category}-Objekten zu ermöglichen, werden MM-Tabellen (many-to-many) benötigt,
2023-03-24 17:32:59 +01:00
um diese Beziehungen in Form zweier Foreign Keys zu speichern.
Die Repository-Klassen können \enquote{leer} gelassen werden,
2023-03-02 02:04:33 +01:00
da zu diesem Zeitpunkt keine erweiterte Auswahllogik für Datenbankanfragen benötigt wird.
Wichtig ist hierbei, dass eine Repository-Klasse existiert. Alle unverzichtbaren
Schnittstellen werden über die Basisklasse \enquote{Repository} geerbt
\cite{bib:typo3-docs-extdev-tut-tea-repositories}.
2023-03-24 17:32:59 +01:00
Mit Abschluss der Phase der Digitization können alle Datenstrukturen im TYPO3-Backend händisch angelegt,
2023-03-02 02:04:33 +01:00
eingesehen, gelöscht und bearbeitet werden.
2023-03-16 03:15:07 +01:00
2023-03-21 17:52:19 +01:00
\section{Digitalization}
In der Phase \textit{Digitalization} werden bestehende Geschäftsprozesse so verändert,
dass mit digitalen Werkzeugen und Datenmodellen gearbeitet werden kann \cite{bib:fengli}.
Damit baut diese Phase auf der vorherigen Phase \enquote{Digitization} auf, um mit den dort
implementierten Datenmodellen zu arbeiten. Im Folgenden werden die Umsetzungen der
erforderlichen Geschäftsprozesse beschrieben.
2023-03-21 17:52:19 +01:00
\subsection{Teilnehmerregistrierung}
2023-03-16 03:15:07 +01:00
Ein essenzieller Teil des Jahresauswahlprobenwerkzeuges ist die Registrierung von Teilnehmern.
Dieses Modul repräsentiert den ersten Berührungspunkt der Winzer mit dem System.
2023-03-23 16:09:48 +01:00
Hiervon profitiert \ac{WM}, weil registrierte Benutzer der Webseite eine Grundvorausetzung
für die Onlineregistrierung von Weinen zu \acp{JAP} sind.
2023-03-16 03:15:07 +01:00
Dem Pflichtenheft ist zu entnehmen, dass es zwei Kategorien von Teilnehmerregistrierungen gibt:
\begin{enumerate}
\item Nutzer ist \ac{WM}-Mitglied
\item Nutzer ist kein \ac{WM}-Mitglied
\end{enumerate}
Der primäre Unterschied zwischen Mitgliedern und Nicht-Mitgliedern ist, dass Mitglieder bereits einen
Stammdatensatz hinterlegt haben.
Dieser Stammdatensatz bildet die Angaben zum Weingut des zu digitalisierendem Anmeldeformulares ab.
Nicht-Mitglieder sind dem System noch gänzlich unbekannt und müssen im Zuge der Registrierung ihres Nutzers
ihre Stammdaten angeben, während sich Mitglieder lediglich einloggen müssen und eine Schaltfläche
\enquote{Teilnehmer werden} betätigen.
Der mit dem \ac{PO} ausgearbeitete UX-Flow der Registrierung sieht vor, dass der Nutzer zunächst gefragt wird,
ob er Mitglied sei oder nicht. Hierzu gibt es je einen Button. Ist der Nutzer ein Mitglied,
wird er auf ein Loginform, mit der Option zur Registrierung weitergeleitet.
Nach erfolgreichem Login, wird ein Teilnehmerobjekt erstellt.
2023-03-24 17:32:59 +01:00
Wählt der Nutzer \enquote{Nein, ich bin kein Mitglied} aus, wird er auf ein Registrierungsformular
weitergeleitet, um einen Nicht-Mitgliederaccount anzulegen. Im Zuge dieser Registrierung werden
2023-03-16 03:15:07 +01:00
Stammdaten zum Weingut angefragt.
Dieser Schritt übersetzt unter anderem den \enquote{Einreicher}-Teil des ursprünglichen Anmeldeformulares,
anbei in \fullref{chap:anhang-anmeldeformular}.
2023-03-16 03:15:07 +01:00
\begin{nicepic}
\includegraphics[width=0.9\textwidth]{images/ux-flow-registrierung.png}
\captionof{figure}{UX-Flow: Registrierung}
\caption*{Quelle: Eigene Darstellung}
\label{fig:uxflow-registrierung}
\end{nicepic}
Da das Brown-Field-Projekt bereits Accountlogins und -Registrierungen implementiert und nutzt,
werden auf diese Lösungen zurückgegriffen, um einen einheitlichen Workflow beizubehalten. Accountregistrierungen werden über den
\enquote{femanager} \cite{bib:typo3-docs-femanager} realisiert, während Logins via TYPO3's nativem
Frontend-Nutzer-Login gelöst werden. Das ist explizit von femanager so angedacht:
\quotecite{Note: Login and a I forgot my password function is part of the core and not part of femanager.}
\cite{bib:typo3-docs-femanager}.
Im Folgenden wird der Registrierungsprozess im Detail beschrieben:\\
Grundlegend gibt es drei relevante Nutzerzustände vor der Registrierung:
\begin{enumerate}
\item Kein Mitglied
\item Mitglied, mit Konto
\item Mitglied, ohne Konto
\end{enumerate}
Diese Prozesse sehen wie folgt aus:
2023-03-21 17:52:19 +01:00
\subsubsection*{Kein Mitglied}
2023-03-16 03:15:07 +01:00
Ist ein Nutzer kein Mitglied, so muss er zunächst einen Account erstellen.
Anfangs wählt dieser Nutzer \enquote{Ich bin kein Mitglied} auf der Registrierungsseite aus.
Daraufhin navigiert der Browser zu einem Registrierungs-Formular.
Hierfür muss eine Email-Adresse und ein Passwort vergeben und den Nutzungsbestimmungen zugestimmt werden.
Im Anschluss erhält der Nutzer eine Bestätigungsemail mit einem Aktivierungslink.
Wird dieser Link geöffnet, wird der Account freigeschalten und ein Login-Feld erscheint.
Nach erfolgreichem Login wird der Nutzer mit einem
Stammdatenformular konfrontiert. Dabei handelt es sich um Angaben zum teilnehmenden Weingut.
Wird dieses Formular abgeschickt, ist die Teilnehmerregistrierung abgeschlossen.
2023-03-21 17:52:19 +01:00
\subsubsection*{Mitglied, mit Konto}
Ist ein Nutzer ein Weinland-Mosel-Mitglied und hat bereits ein Mitgliedskonto, muss dieser auf der Registrierungsseite
2023-03-16 03:15:07 +01:00
\enquote{Ich bin ein Mitglied} auswählen. An dieser Stelle navigiert der Browser zu einem Login-Formular.
Hier kann sich das Mitglied anmelden. Tut es dies erfolgreich, erstellt der Controller einen neuen
Teilnehmer-Eintrag für den Frontend-Nutzer und fügt den Frontend-Nutzer der Nutzergruppe \enquote{Teilnehmer} hinzu.
Damit ist die Teilnehmerregistrierung abgeschlossen.
2023-03-16 03:15:07 +01:00
2023-03-21 17:52:19 +01:00
\subsubsection*{Mitglied, ohne Konto}
2023-03-24 17:32:59 +01:00
Ist ein Nutzer ein Mitglied, hat aber kein Mitgliedskonto, muss dieser auf der Registrierungsseite
2023-03-16 03:15:07 +01:00
\enquote{Ich bin ein Mitglied} auswählen. An dieser Stelle navigiert der Browser zu einem Login-Formular.
Auf diesem Login-Formular existiert ein Button \enquote{Jetzt registrieren}, sowie ein Hinsweistext dazu.
Da der Nutzer noch keinen Account hat, muss dieser auf \enquote{Jetzt registrieren} klicken.
Daraufhin navigiert der Browser zu einem Registrierungsformular, das eine Email-Adresse, ein Passwort
und die Zustimmung zur Datenverarbeitung benötigt. Ist dieses Formular abgeschickt, erhält das Mitglied
eine Email mit einem Bestätigungslink. Wird dieser Bestätigungslink angeklickt, wird das Mitgliedskonto
freigegeben und es öffnet sich ein Login-Formular, beschrieben in \enpointy{Mitglied, mit Konto}.
2023-03-16 03:15:07 +01:00
2023-03-21 17:52:19 +01:00
\subsubsection*{Umsetzung}
Zunächst wurde ein simples Weichen-Content-Element erstellt.
2023-03-16 03:15:07 +01:00
Dieses Content-Element hat die Parameter \enquote{question}, \enquote{answ-1-link}, \enquote{answ-1-text},
\enquote{answ-2-link} sowie \enquote{answ-2-text}.
2023-03-24 17:32:59 +01:00
Der Zweck dieses Content-Elementes ist es, Nutzer basierend auf einer ausformulierten Frage auf eine
2023-03-16 03:15:07 +01:00
von zwei Seiten weiterzuleiten. Anschließend wurden Registrierungen über Femanager-Plugin-Content-Elemente
realisiert.
Anpassungen der versendeten Emails erfolgen durch Überschreiben der Email-Templates von Femanager.
2023-03-24 17:32:59 +01:00
Weiterleitungen zu bestimmten Seiten, nachdem ein Nutzer spezielle Events ausgelöst hat, können über TypoScript
2023-03-16 03:15:07 +01:00
konfiguriert werden \cite{bib:typo3-docs-femanager}. Logins werden über das TYPO3-Native Loginformular
2023-03-24 00:13:34 +01:00
gelöst. Im TYPO3-Loginformular können Weiterleitungen zu spezialisierten Seiten im Backend-UI festgelegt werden.
2023-03-16 03:15:07 +01:00
\cite{bib:typo3-docs-felogin}.
2023-03-24 17:32:59 +01:00
Für alle funktionalen Belange wird ein TYPO3-Plugin registriert. Dieses Plugin verfügt über einen
2023-03-16 03:15:07 +01:00
ActionController, der Nutzeranfragen an PHP-Funktionen (\enquote{Actions})
bindet.
2023-03-24 17:32:59 +01:00
In diesen Actions werden Fehlerbehandlungen durchgeführt, Datenmodelle der Domäne erstellt und in der
Datenbank persistiert, sowie Daten für die Anzeige im Frontend aufbereitet \cite{bib:typo3-docs-extbase}.
2023-03-16 03:15:07 +01:00
Neue Datenobjekte werden in Repositories registriert \cite{bib:typo3-docs-extdev-tut-tea-repositories}. Diese Repositories sind Aggregate des Controllers,
werden jedoch nach dem \enquote{Inversion of Control}-Prinzip via Dependency Injection instanziiert und
der ActionController-Klasse über Methode übergeben \cite{bib:typo3-docs-di}.
2023-03-24 17:32:59 +01:00
Als problematisch erweisen sich hierbei bidirektionale Verbindungen zwischen Datenmodellen, wenn die Foreign Keys
über das SQL-Schlüsselwort \enquote{AUTO\_INCREMENT} in der Datenbank generiert werden.
Beispielsweise, muss ein MasterRecord, der Betriebsinformationen speichert, bidirektional an ein Teilnehmerobjekt
gebunden werden. Hierzu wird jedem der Elemente jeweils der Foreign Key des anderen übergeben.
Als Foreign Keys werden hierfür die jeweiligen \acp{UID} herangezogen, da diese Werte durch
\enquote{AUTO\_INCREMENT} auf der Datenbankebene erzeugt werden und garantiert einzigartig je Datenbanktabelle sind
\cite{bib:w3schools-auto-increment}.
Es gilt also, dass ein MasterRecord $a$ die Teilnehmer\ac{UID} von einem Teilnehmer $b$ hält und dass
$b$ die MasterRecord\ac{UID} von $a$ hält.
Die Problematik hierbei ist, dass diese \acp{UID} erst nach dem Persistieren in der Datenbank bekannt sind,
da diese Werte erst im Zuge der Persistierung erstellt werden \cite{bib:w3schools-auto-increment}.
Die Lösung hierfür ist, beide Elemente zu erstellen und zu persistieren, erst danach ihre \acp{UID} gegenseitig
2023-03-16 03:15:07 +01:00
bekannt machen um sie danach erneut zu persistieren.
\subsection{Weinregistrierung}
Ein Basismerkmal des Jahresauswahlprobenwerkzeuges ist die Möglichkeit, Weine zu Jahresauswahlproben
anzumelden. Dieser Schritt übersetzt unter anderem die verbleibenden Formfelder des
ursprünglichen Anmeldeformulares, anbei in \fullref{chap:anhang-anmeldeformular} in den digitalen Workflow.
Für die Weinanmeldung spielt die Mitgliedsschaft eines Teilnehmers keine Rolle. Es wird lediglich ein
Frontend-Nutzer der Nutzergruppe \enquote{Teilnehmer} benötigt. Dieser Nutzer hat, wenn angemeldet,
Zugriff auf eine Auflistung aller zeitlich freigegebenen Jahresauswahlproben.
Soweit der Registrierungszeitraum dieser Jahresauswahlprobe den aktuellen Zeitpunkt miteinschließt,
wird eine \enquote{Jetzt Wein anmelden}-Schaltfläche angeboten.
2023-03-23 16:09:48 +01:00
Dadurch, dass Anmeldeformulare elektronisch und automatisiert verarbeitet werden, sinkt der Aufwand,
der seitens \ac{WM} für Anmeldungen gestemmt werden muss. Das ist so, da diese Formular nun nicht mehr von
Mitarbeitern bearbeitet werden müssen. Davon profitiert \ac{WM}, da diese Zeit nun anderweitig genutzt werden kann.
\begin{nicepic}
\includegraphics[width=0.9\textwidth]{images/ux-flow-teilnahme.png}
\captionof{figure}{UX-Flow: Weinanmeldung}
\caption*{Quelle: Eigene Darstellung}
\label{fig:uxflow-weinanmeldung}
\end{nicepic}
\subsubsection*{IT-Sicherheit}
Es ist wichtig zu erwähnen, dass solche Überprüfungen,
wie das Aktivsein eines Registrierungszeitraumes einer \ac{JAP}, grundsätzlich im Backend, d.h. serverseitig
auf der betroffenen Webseite (in diesem Beispiel der Weinanmeldungsseite) durchgeführt werden.
Das Verstecken der zugehörigen
Schaltfläche im Frontend dient lediglich der User-Experience und stellt keine Sicherheitsvorkehrung dar.
2023-03-23 16:09:48 +01:00
Das ist essenziell, da eine URL, auch wenn für sie keine Schaltfläche existiert, dennoch aufgerufen werden kann.
Da Jahresauswahlprobennummern (\acp{UID}) fortlaufend sind, ist es trivial URLs für Weinanmeldungen
beliebiger Jahresauswahlproben herzuleiten. Insofern ist es von großer Wichtigkeit sicherzustellen,
dass der Server solche Anfragen grundsätzlich selbst prüft und gegebenenfalls verneint.
\subsubsection*{Das Formular}
Aufgrund dessen, dass TYPO3 die Fluid Templating Engine verwendet \cite{bib:typo3-fluid},
werden Formulare und Formfelder mit den entsprechenden Fluid-Form-ViewHelpern aufgebaut.
Diese ViewHelper repräsentieren und erstellen gleichnamige HTML-Tags und fügen diesen spezielle
Attribute zur Identifizierung in Submit-Aufrufen hinzu \cite{bib:typo3-docs-fluid-form-viewhelpers}.
Grundsätzlich entstehen hierbei drei Kategorien von Werten, die es im Formular abzubilden gilt:
\paragraph*{Inputfelder} sind triviale Formfelder, die nicht durch andere Datensätze beschränkt werden.
Beispiele für Inputfelder sind: Weinbeschreibung, Jahrgang und Alkoholgehalt.
Inputfelder wurden mit simplen Input-Tags umgesetzt und erhielten nach Bedarf \textit{required} und
\textit{pattern}-Attribute. Diese Attribute beschreiben jeweils, ob ein Formfeld ein Pflichtfeld ist und
mit welcher Regular Expression der Formfeldinhalt abzugleichen ist \cite{bib:w3schools-input}.
Die Formfeldwerte können unverändert in der Datenbank persistiert werden.
\paragraph*{SelectSingle} sind Formfelder, die dem Nutzer eine Auswahl aus $n$ Elementen aus
anderen Datenbanktabellen geben. Der Nutzer muss sich für genau ein Element entscheiden.
Beispiele für SelectSingle-Formfelder sind: Weinlage, Qualitätsstufe, Rebsorte und Geschmacksangabe.
SelectSingle-Formfelder werden durch Select-HTML-Tags abgebildet. Der TYPO3-Form-ViewHelper für
\enquote{Select} akzeptiert eine Liste an Auswahlmöglichkeiten und erstellt selbstständig Option-HTML-Tags
für diese.
Die Formfeldwerte von SelectSingle-Formfeldern sind die
2023-03-23 16:09:48 +01:00
\acp{UID} des jeweils ausgewähltem Elementes \cite{bib:typo3-docs-fluid-form-viewhelpers}.
\\
\\
Aufgrund dessen, dass das Weinlagen-Drop-Down-Menü über 170 Einträge führt, wurde eine Suchmöglichkeit implementiert. Diese ist lediglich ein Textfeld, das bei jeder Eingabe allen Option-Tags der Weinlage,
deren Anzeigewert nicht der Suche entspricht, das Stilattribut \enquote{display: none;} auferlegt.
Somit sind diese nicht mehr sichtbar.
\\
\\
Eine komplexe Ausnahme stellt das SelectSingle-Formfeld \enquote{Category} dar, da TYPO3-Kategorien
Baumstrukturen sind \cite{bib:typo3-docs-sys-category}.
Um die Eltern-Kind-Beziehung der Baumstruktur erstichtlich zu machen, werden die Option-HTML-Tags einzeln rekursiv gerendert. Zunächst werden sämtliche Kategorien, deren
\ac{PID} 0 ist, dargestellt. Diese Elemente sind direkte Kinder des unsichtbaren Wurzelelementes. Für jede dieser Kategorien $a$ wird nun ein
Fluid-Partial aufgerufen,
das alle Kategorien $b$ darstellt, für die gilt: $b.pid = a.uid$. Diese Darstellung erfolgt durch einen erneuten rekursiven Aufruf dieses Partials.
In jeder Darstellung wird der Kategoriename, geprefixt mit
$n$ Leerzeichen, dargestellt, mit $n = Rekursionstiefe$. Somit entsteht ein Drop-Down-Menü, das
alle Kategorien in einer eindimensionalen Liste darstellt. Diese Liste ist nach einer Preorder-Traversierung
des Kategoriebaumes sortiert und desto tiefer ein Element im Baum ist, desto weiter ist es eingerückt.
Damit sieht das Drop-Down-Menü aus wie eine Baumstruktur.
\\
\\
Diese Herangehensweise erzeugt schlüssigen und lesbaren Programmcode und lässt sich unkompliziert umsetzen.
2023-03-23 16:09:48 +01:00
Das senkt Entwicklungskosten und erhöht den Profit des Endkunden, da hierdurch weniger Zeit aufgewandt wird.
Rekursiv aufgerufene For-Schleifen, die sich selbst erneut für alle Elemente aufrufen,
2023-03-24 00:11:47 +01:00
können zu einem Performanzproblem führen \cite{bib:schwarzer-vorlesung-alg}.
Daher wird im Folgenden die Zeitkomplexität dieser Rekursionsfunktion betrachtet.
Grundlegend, kann für diese Funktion kein Master-Theorem angewandt werden,
2023-03-24 00:11:47 +01:00
da es sich hierbei nicht um einen Divide-and-Conquer-Algorithmus handelt.
Das ist so, da das in der Rekursion weitergereichte Problem nicht kleiner wird,
sondern gleich groß bleibt.
2023-03-24 00:11:47 +01:00
Das verletzt die Bedingung $b>1$ des Master-Theorem, definiert als $T(n) = a*T(\frac{n}{b})+f(n)$
\cite{bib:schwarzer-vorlesung-alg}.
Der Algortihmus besteht aus $m, m \in \mathbb{N}$ verschachtelten For-Schleifen
gleicher Länge.
Somit ist die Zeitkomplexität $O(n^m)$. Normiert dargestellt beträgt die Zeitkomplexität $O(n^2)$. Das lässt sich experimentell bestätigen.
\begin{nicepic}
\includegraphics[width=0.70\textwidth]{images/timecomplexity-category.png}
\captionof{figure}{Stichprobenartige Laufzeitanalyse des\\Kategorie-Renderers, gegenüber einer\\ quadratischen Kurve}
\caption*{Quelle: Eigene Darstellung}
\label{fig:timecomplexity-category}
\end{nicepic}
Auf Optgroup-HTML-Tags wurde bewusst verzichtetet.
2023-03-24 00:11:47 +01:00
Grund dafür ist, dass Optgroup-Elemente an sich nicht im Dropdown auswählbar sind.
Das stellt ein Problem dar, da beispielsweise die Kategorie \enquote{Riesling},
die die Unterkategorien \enquote{Trockener Riesling} und \enquote{Halbtrockener Riesling} beinhalten könnte,
auch direkt auswählbar sein sollte. Zudem besitzen Kategorie-Elemente kein Attribut das auf die Präsenz
von Unterkategorien hindeutet \cite{bib:typo3-docs-sys-category}, womit eine Unterscheidung zwischen
2023-03-24 00:11:47 +01:00
Baumblättern und -Zweigen nicht ohne weiteres möglich wäre. Diese Entscheidung wäre jedoch
benötigt, um zwischen einem Optgroup-Tag und einem Option-Tag abzuwägen.
\paragraph*{SelectMultiple} sind Formfelder, die dem Nutzer eine Auswahl aus $n$ Elementen aus einer anderen
Datenbanktabelle geben. Der Nutzer kann sich für eine beliebige Anzahl dieser, eingeschlossen null, entscheiden.
Ein Beispiel für SelectMultiple-Formfelder ist: Weineigenschaften.
TYPO3-Fluid implementiert hierfür keinen ViewHelper \cite{bib:typo3-docs-fluid-form-viewhelpers},
also wurde eine eigene Lösung entworfen: Der Nutzer soll aus einer Menge $A$ wählen.
Für alle Elemente $a \in A$
wird ein Checkbox-Feld erstellt. Dieses Element trägt den Anzeigewert \enquote{<a.title>} und den
Wert \enquote{<formfeldname>-true}.
Ist also eine dieser Checkboxen angehakt, hat sie den zuvor genannten Wert. Falls nicht, trägt sie keinen Wert.
Weil alle angehakten Checkboxen dieses Formfeldes den selben Wert tragen, ist es PHP-Seitig trivial
eine Liste aller angehakten Checkbox-Ids dieses Formfeldes aus der Liste aller Formfeldparameter zu extrahieren.
Hierfür wird die eingebaute PHP-Funktion \enquote{array\_keys} verwendet. Diese Funktion gibt alle
Keys eines Arrays in Form eines numerisch indizierten Arrays zurück.
Der optionale Parameter \enquote{filter\_values} bestimmt, dass ausschließlich die Keys
der Key-Value-Pairs, die einen bestimmten
2023-03-23 22:24:47 +01:00
Wert tragen, extrahiert werden \cite{bib:php-array-keys}. D.h., der Funktionsaufruf filtert alle Keys und somit alle
Formfeld-IDs des Formfeldparameter-Arrays heraus, die den Wert \enquote{<formfeldname>-true} haben. Das ist eine Liste
aller Formfeld-IDs der Checkboxen des SelectMultiples, die angehakt wurden.
2023-03-24 00:16:24 +01:00
Mit der eingebauten PHP-Funktion \enquote{array\_map} wird nun eine Operation auf alle Schlüssel
der Liste angewandt, die \enquote{strlen('formfeldname-')} Zeichen, von links ausgehend, von der Formfeld-ID
2023-03-23 16:09:48 +01:00
entfernt. Somit wird beispielsweise die Formfeld-ID \enquote{winekind-18} zu \enquote{18} transformiert. Übrig bleiben die \acp{UID} aller angehakten Elemente $a$, in Form einer Zeichenkente.
Über die eingebaute PHP-Funktion \enquote{intval} ist es trivial diese zu Zahlen zu übersetzen,
wodurch die tatsächlichen Objekte aus der Datenbank angefragt werden können.
2023-03-23 22:24:47 +01:00
\subsection{PDF- und QR-Code-Generierung}
Das dynamische Erstellen und Ausgeben des Versandbeilageblattes als PDF ist ein essenzieller Bestandteil des
Jahresauswahlprobenwerkzeuges, da dieses PDF die Schnittstelle zwischen ankommenden Weinen und dem System darstellt.
Daher ist der Profit, der durch dieses Werkzeug generiert wird, ohne dieses PDF stark eingeschränkt, da
einkommende Weine händisch, von Mitarbeitern, zugeordnet werden müssten.
Wie im \fullref{chap:stand-der-forschung} erläutert, werden für die dynamische
Generierung dieses PDFs die Bibliotheken \enquote{chillerlan/php-qrcode} und
\enquote{mpdf/mpdf} herangezogen und über Composer installiert.
\subsubsection{QR-Code-Generierung}
Der QR-Code beinhaltet lediglich die Wein-\ac{UID} anstatt einer vollständigen URL. Hintergrund dessen ist, dass
die URL, die benötigt ist, um einen Wein einzuscannen, bis auf die Wein-\ac{UID} immer identisch ist.
Somit wird redundanz vermieden.
Es ist Aufgabe der QR-Code-App, die den Code einscannt, aus der Wein-\ac{UID} eine vollständige URL herzuleiten.
Um Resourcen zu sparen und somit den Profit zu erhöhen, wird der QR-Code zu einem Base64-kodiertem Bild gerendert.
Das ist der Standardrückgabewert des QR-Code-Generators
und erfordert somit keine nähere Konfiguration. Ebenfalls lässt sich ein Base64-kodiertes Bild als Quellurl eines
IMG-HTML-Tags angeben, womit das Bild eingebettet ist. Hier wird der Profit erhöht, indem Arbeitszeit gespart wird,
die sonst in das anderweitige Einbetten eines Bildes in einem PDF mit \enquote{mpdf} fließen müsste.
Die QR-Codegenerierung funktioniert konkret, indem ein neues QRCode-Objekt der QRCode-Klasse erstellt wird.
Diese Klasse nimmt ein QROptions-Objekt im Konstruktor, das in diesem Falle einige Stilattribute mit sich trägt.
Das QRCode-Objekt bietet nun eine Methode \enquote{render} an, die, sofern nicht anders konfiguriert, den QR-Code als
Base64-kodiertes Bild zurückgibt \cite{bib:chillerlan-php-qrcode}.
\subsubsection{PDF-Generierung}
Firmenintern ist es Standard das Aussehen sowie die Inhalte der PDF-Dokumente, die \enquote{mpdf} erzeugt, mit HTML zu definieren,
das an \enquote{mpdf} gereicht wird. Um die Gestaltung und die Präsentation von Variablen in der HTML-Zeichenfolge technisch
kontinuierlich mit dem restlichen Projekt zu halten und um eine gute Wartbarkeit zu gewährleisten,
wird diese HTML-Zeichenfolge mit TYPO3-Fluid getemplated. Das heißt, dass eine HTML-Templatedatei bereitgestellt wird,
diese mit TYPO3-Fluid befüllt wird und in PHP gerendert wird, um eine HTML-Zeichenkette als Ergebnis zu erhalten.
2023-03-24 00:11:47 +01:00
Hierfür wird ein TYPO3-StandaloneView des instanziiert, mit einem Pfad zur Template-Datei ausgestattet, Variablen angegeben,
2023-03-23 22:24:47 +01:00
die in Fluid verfügbar sein sollen und anschließend über die \enquote{render}-Methode zu einem String gerendert
\cite{bib:typo3-ref-standalone-view}.
Anschließend wird ein \enquote{mpdf}-Objekt erstellt und mit einer rudimentären Konfiguration in Form eines Arrays im Konstruktor
konfiguriert. Diese Konfiguration definiert in diesem Falle Seitenabstände, Papierformat, Zeichenkodierung und Schriftarten.
Abschließend wird dem \enquote{mpdf}-Objekt das zuvor generierte HTML übergeben und über die Methode \enquote{OutputBinaryData}
als Bytes zurückgegeben und in einer Variable gespeichert \cite{bib:mpdf-ref}.
Um dieses PDF-Dokument über die Verbindung an den Nutzer zu übertragen, wird ein TYPO3-Response-Objekt erstellt.
Über dieses Response-Objekt werden einige Header gesetzt und direkt übertragen. Dieser Header sind Content-Type und Content-Length.
Abschließend werden als Response-Body die Bytes des generierten PDFs abgeschickt. Damit ist die Verbindung beendet und das
PDF zum Nutzer übertragen.
2023-03-24 00:11:47 +01:00
\subsection{Schnittstelle QR-Code-Scanner}
Es ist angedacht, dass Mitarbeiter über die App \enquote{QRBot} den QR-Code auf dem Einlieferungsschein einscannen.
Diese App ermöglicht es Nutzern für jeden eingescannten Code eine URL zu öffnen und den Wert des QR-Codes anstelle eines Platzhalters
in der URL einzufügen.
Hierfür bietet das Jahresauswahlprobenwerkzeug eine Schnittstelle bzw. eine Seite an, die eine Wein-\ac{UID} als
URL-kodierten GET-Parameter annimmt und diesen Wein als \enquote{eingegangen} markiert.
Um sicherzustellen, dass Weine nicht unautorisiert markiert werden, müssen sich Mitarbeiter mit einem Nutzerkonto
authentifizieren. Dieses Nutzerkonto muss Teil einer Mitarbeiter-Nutzergruppe sein.
Das Nutzerkonto wird von Redakteuren oder Administratoren im TYPO3-Backend erstellt und benötigt keiner Registrierung.
Nach einer Anmeldung bleibt diese Sitzung aktiv und verfällt erst nach längerer Inaktivität.
Wird ein Wein als \enquote{eingegangen} markiert, wird der betroffene Teilnehmer per Email informiert.
Hierzu wird die FluidEmail-Klasse des TYPO3-Cores herangezogen.
Sollte ein Wein bereits als \enquote{eingegangen} markiert sein, wird keine Email verschickt und dem Mitarbeiter wird kommuniziert,
dass keine Änderungen vorgenommen wurden.
Abschließend werden im Frontend allgemeine Daten über den Wein angezeigt, damit Mitarbeiter sich sicher sein können,
den richtigen Wein eingescanned zu haben.
\subsection{Jahresauswahlproben- und Wein-Detailansichten}
Weine und Jahresauswahlproben sollen unter bestimmten Gegebenheiten einsichtig sein.
Hierzu gibt es eine Auflistung aller Jahresauswahlproben. Diese sind anklickbar, um eine Detailansicht der ausgewählten
Jahresauswahlprobe zu öffnen. Hier wird neben Metadaten der Jahresauswahlprobe eine Liste aller zur Einsicht berechtiger Weine
angezeigt. Diese Weine sind anklickbar, um auf eine Detailansicht der Weine zu gelangen.
Die Detailansichten für Jahresauswahlproben und Weine benötigen spezieller Autorisierung.
Diese sind: Jahresauswahlproben sind nur einsichtig, wenn sich das aktuelle Datum innerhalb des
Sichtbarkeitszeitraumes der Jahresauswahlprobe befindet.
Detailansichten für Weine sind immer für den zugehörigen Teilnehmer einsichtig.
Nach Abschluss einer Jahresauswahlprobe sind alle ihr angehörigen Weine öffentlich einsichtig.
Das hat den Hintergrund, dass Jahresauswahlproben Blindverkostungen sind
und niemand die Möglichkeit haben sollte, im Voraus Informationen über die teilnehmenden Weine in Erfahrung zu bringen.
Die Ergebnisse der Jahresauswahlproben sind öffentlich, also sind es die Weine nach Abschluss einer \ac{JAP} auch.
Mitarbeiter von Weinland Mosel, wenn mit einem solchen Account angemeldet, haben immer Einsicht in Wein-Detailansichten.
Die Wein-Detailseite verfügt außerdem über einen \enquote{Versandetikett drucken}-Button, der auf das Versand-PDF verlinkt.
Dieser Button ist nur für den zugehörigen Teilnehmer und Mitarbeiter verfügbar.
Diese Daten, Fakten und Restriktionen werden serverseitig kontrolliert, um Manipulationen des Nutzers auszuschließen.
Um das zu realisieren werden Daten mit Fluid-Templates konditionell dargestellt und über Fluid-ViewHelper Links
zu anderen Ansichten generiert. Diese ViewHelper übergeben Parameter. Die hierfür relevanten Parameter der verschiedenen
Ansichten sind beispielsweise Wein-\acp{UID} und \ac{JAP}-\acp{UID}. Um Informationen über den angemeldeten Nutzer,
wie beispielsweise seiner Teilnehmernummer oder seiner Nutzergruppenzugehörigkeit, zu erlangen, wird sich
der Extbase-nativej Domain-Model-FrontendUser-Klasse bedient \cite{bib:typo3-ref-extbase-model-feuser}.
\subsection{CSV-Export}