feat: probelesen

This commit is contained in:
2023-03-30 18:59:27 +02:00
parent ce8b1ce5fa
commit 4ee7b22db6
19 changed files with 100 additions and 93 deletions

View File

@@ -6,8 +6,8 @@ Brown-Field Projekt \cite{bib:schwarzer-vorlesung-swa} in Form einer TYPO3-Erwei
Es ist anzumerken, dass das aus \fullref{chap:anforderungserfassung} hervorgehende Pflichtenheft im Rahmen geplanter und
opportunistischer Gespräche mit dem \ac{PO} geringfügige Änderungen erfahren wird.
\section{Setup einer TYPO3-Erweiterung}
TYPO3-Erweiterungs werden via Composer installiert \break\cite{bib:typo3-docs-managing-extensions}.
\section{Setup der TYPO3-Erweiterung}
TYPO3-Erweiterungen werden via Composer installiert \break\cite{bib:typo3-docs-managing-extensions}.
Um eine TYPO3-Erweiterung zu erstellen, muss also ein Composer-Paket erstellt werden.
Um vermeidbare Komplexität zu verhindern, wird das Composer-Paket, welches die hier betrachtete
TYPO3-Erweiterung darstellt, lokal in den versionierten Ordner \enquote{packages} gelegt.
@@ -17,7 +17,7 @@ Somit wird ein Composer-Paket nur für dieses Projekt bereitgestellt,
ohne den Aufwand zu betreiben, der üblicherweise mit dem Bereitstellen eines Paketes einhergeht.
\\
\\
Um das grundlegende Setup einer TYPO3-Erweiterung effizient durchzuführen, wurde eine
Um das grundlegende Setup einer TYPO3-Erweiterung effizient durchzuführen, wird eine
existierende Erweiterung mit vergleichbarem Funktionsumfang kopiert, umbenannt und eingefügt.
Spezifisch ist dieser \enquote{vergleichbare Funktionsumfang}, dass es ebenfalls Datenmodelle und hochpersonalisierte
Frontendlogik in Bezug auf die zuvor genannten Datenmodelle gibt.
@@ -28,6 +28,7 @@ in einer Art und Weise, die ermöglicht, dass diese elektronisch weiterverarbeit
Des Weiteren befasst sich diese Phase mit der Automatisierung und Befüllung dieser Daten,
wie zum Beispiel durch Web-Formulare \cite{bib:verhoef}.
Das bedeutet, dass in dieser Phase Datenobjekte definiert und implementiert werden.
Ebenfalls werden anhand der Papier-Formulare Web-Formulare gebaut, damit Nutzer diese Datenobjekte erstellen können.
Ein Datenobjekt besteht nach firmeninternen Konventionen aus zumindest
vier Komponenten:
\begin{description}
@@ -50,28 +51,28 @@ angefertigt und in Rücksprache mit dem \ac{PO} finalisiert.
\begin{nicepic}
\includegraphics[width=1\textwidth]{images/objektrelationen-weinlandmosel-einlieferungswerkzeug.png}
\captionof{figure}{Objektrelationen}
\caption*{Quelle: Eigene Darstellung: Weinland Mosel Einlieferungswerkzeug}
\captionof{figure}{Objektrelationen: Weinland Mosel Einlieferungswerkzeug}
\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
Nachdem in Erfahrung gebracht wird, welche konkreten Datenobjekte benötigt werden,
werden Attribute dieser Objekte dem Pflichtenheft entnommen. Diese werden 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.
Das hat den Vorteil, dass TYPO3-Categories bereits native Bestandteile eines TYPO3-Redaktionssystemes sind
und alle relevanten Attribute anbieten. Diese sind Titel,
Parentkategorie und Beschreibung.
Das Parent-Attribut ist benötigt, da $n$ dieser Attribute einen Attributbaum bilden
Das Parent-Attribut ist nötig, da $n$ dieser Attribute einen Attributbaum bilden
\cite{bib:typo3-docs-sys-category}.
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,
Rebsorte, Geschmacksangabe, Weineigenschaften und Qualitätsstufe sollen eigene Datentypen,
anstatt einfacher Zeichenfolgen sein.
Ziel dessen ist, dass sich Nutzer für einen vorgefertigten, nominalen Eintrag in einem Dropdown-Menü
entscheiden müssen und diese Auswahlmöglichkeiten im TYPO3-Backend pflegbar sind.
entscheiden müssen und dass diese Auswahlmöglichkeiten im TYPO3-Backend pflegbar sind.
Weinlagen sind im Brown-Field-Projekt bereits vorhanden, also sollen hierfür existierende Daten
wiederverwendet werden.
Je Wein sollen beliebig viele Weineigenschaften auswählbar sein. Wettbewerbskategorien,
@@ -103,10 +104,10 @@ Dem Pflichtenheft ist zu entnehmen, dass es zwei Kategorien von Teilnehmerregist
\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
Der primäre Unterschied zwischen Mitgliedern und Nichtmitgliedern ist, dass Mitglieder bereits einen
Stammdatensatz hinterlegt haben.
Dieser Stammdatensatz bildet die Angaben zum Weingut des zu digitalisierenden Anmeldeformulares ab.
Nicht-Mitglieder sind dem System noch gänzlich unbekannt und müssen im Zuge der Registrierung ihres Nutzers
Nichtmitglieder 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,
@@ -114,7 +115,7 @@ ob er Mitglied sei oder nicht. Hierzu gibt es je einen Button. Ist der Nutzer ei
wird er auf ein Loginformular, mit der Option zur Registrierung weitergeleitet.
Nach erfolgreichem Login, wird ein Teilnehmerobjekt erstellt.
Wählt der Nutzer \enquote{Nein, ich bin kein Mitglied}, wird er auf ein Registrierungsformular
weitergeleitet, um einen Nicht-Mitgliederaccount anzulegen. Im Zuge dieser Registrierung werden
weitergeleitet, um einen Nichtmitgliederaccount anzulegen. Im Zuge dieser Registrierung werden
Stammdaten zum Weingut angefragt.
Dieser Schritt übersetzt unter anderem den \enquote{Einreicher}-Teil des ursprünglichen Anmeldeformulares,
anbei in \fullref{chap:anhang-anmeldeformular}.
@@ -130,7 +131,7 @@ Da das Brown-Field-Projekt bereits Accountlogins und -registrierungen implementi
wird 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 TYPO3s nativem
Frontend-Nutzer-Login gelöst werden. Das ist explizit von \enquote{femanager} so angedacht:
Frontend-Nutzer-Login gelöst werden. Das ist explizit von \enquote{femanager} 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:
@@ -196,9 +197,10 @@ Datenbank persistiert sowie Daten für die Anzeige im Frontend aufbereitet \cite
Neue Datenobjekte werden in Repository-Objekten registriert
\break\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 eine Methode übergeben \cite{bib:typo3-docs-di}.
ActionController-Objekten über Methoden übergeben \cite{bib:typo3-docs-di}.
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.
über das SQL-Schlüsselwort
\break\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
@@ -216,7 +218,7 @@ Ein Basismerkmal des Jahresauswahlprobenwerkzeuges ist die Möglichkeit, Weine z
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,
Frontend-Nutzer der Nutzergruppe \enquote{Teilnehmer} erfordert. 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.
@@ -295,7 +297,7 @@ Daher wird im Folgenden die Zeitkomplexität dieser Rekursionsfunktion betrachte
Für diese Funktion kann kein Master-Theorem angewandt werden,
da es sich hierbei nicht um einen \enquote{Divide-and-Conquer-Algorithmus} handelt.
Das ist so, da das in der Rekursion weitergereichte Problem nicht kleiner wird,
sondern gleich groß bleibt.
sondern gleich groß bleibt. Demnach ist $b = 1$.
Das verletzt die Bedingung $b>1$ des Master-Theorems, definiert als $T(n) = a*T(\frac{n}{b})+f(n)$
\cite{bib:schwarzer-vorlesung-alg}.
Der Algorithmus besteht aus $m \in \mathbb{N}$ verschachtelten For-Schleifen
@@ -309,7 +311,7 @@ Somit ist die Zeitkomplexität $O(n^m)$. Normiert dargestellt beträgt die Zeitk
\label{fig:timecomplexity-category}
\end{nicepic}
Auf Optgroup-HTML-Tags wurde bewusst verzichtetet.
Auf Optgroup-HTML-Tags wird bewusst verzichtetet.
Grund dafür ist, dass Optgroup-Elemente an sich nicht im Dropdown-Menü 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,
@@ -323,23 +325,26 @@ Datenbanktabelle geben. Der Nutzer kann sich für eine beliebige Auswahl dieser,
Ein Beispiel für SelectMultiple-Formfelder sind 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.
also wird 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.
wird ein Checkbox-Feld erstellt. Dieses Element trägt den Anzeigewert \enquote{<a.title>},
den ID- und Namenswert \enquote{<formfeldname>-<a.uid>} und den
Formularwert \enquote{<formfeldname>-true}.
Ist also eine dieser Checkboxen angehakt, hat sie den zuvor genannten Formularwert. Falls nicht, trägt sie keinen Formularwert.
Weil alle angehakten Checkboxen dieses Formfeldes den selben Namenswert tragen, ist es phpseitig trivial
eine Liste aller angehakten Checkbox-Namen 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
Wert tragen, extrahiert werden \cite{bib:php-array-keys}. D.h., der Funktionsaufruf filtert alle Keys und somit alle
Wert (der Formwert) 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.
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
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 Zeichenkette.
aller Formfeld-Namen der Checkboxen des SelectMultiples, die angehakt wurden.
Mit der eingebauten PHP-Funktion \enquote{array\_map} wird nun eine Operation auf alle Werte
der Liste angewandt, die
\break\enquote{strlen('<formfeldname>-')} Zeichen, von links ausgehend, vom Formfeld-Name
entfernt. Somit wird beispielsweise der Formfeld-Name \enquote{winekind-18} zu \enquote{18} transformiert.
Übrig bleiben die extrahierten \acp{UID} aller angehakten Elemente $a$, in Form einer Zeichenkette.
Ü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.
@@ -355,9 +360,9 @@ Generierung dieses PDFs die Bibliotheken \enquote{chillerlan/php-qrcode} und
\subsubsection{QR-Code-Generierung}
Der QR-Code beinhaltet lediglich die Wein-\ac{UID} anstatt einer vollständigen URL. Hintergrund dessen ist, dass
die benötigte URL, um einen Wein einzuscannen, bis auf die Wein-\ac{UID} immer identisch ist.
Somit wird redundanz vermieden.
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 effizient zu arbeiten, wird der QR-Code zu einem base64-kodiertem Bild gerendert.
Um effizient zu arbeiten, wird der QR-Code zu einem base64-kodierten Bild gerendert.
Das ist der Standardrückgabewert des QR-Code-\break{}Generators
und erfordert somit keine nähere Konfiguration. Ebenfalls lässt sich ein base64-kodiertes Bild als Quell-URL eines
IMG-HTML-Tags angeben, womit das Bild eingebettet ist. Das spart Arbeitszeit,
@@ -385,6 +390,7 @@ Um dieses PDF-Dokument über die Verbindung an den Nutzer zu übertragen, wird e
Über dieses Response-Objekt werden einige Header gesetzt und direkt übertragen. Diese Header sind Content-Type und Content-Length.
Abschließend werden als Response-Body die Bytes des generierten PDFs übertragen. Damit ist die Verbindung beendet und das
PDF zum Nutzer übertragen.
\clearpage
\subsection{Jahresauswahlproben- und Wein-Detailansichten}
Weine und Jahresauswahlproben sollen unter bestimmten Gegebenheiten einsehbar sein.
@@ -395,7 +401,7 @@ Die Detailansichten für Jahresauswahlproben und Weine benötigen spezielle Auto
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 ihrer Jahresauswahlprobe sind alle ihr angehörigen Weine öffentlich 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 Jahresauswahlprobe auch.
@@ -408,11 +414,9 @@ zu anderen Ansichten generiert. Diese ViewHelper übergeben Parameter. Die hierf
Ansichten sind beispielsweise Wein-\acp{UID} und Jahresauswahlproben-\acp{UID}. Um Informationen über den angemeldeten Nutzer,
wie beispielsweise seiner Teilnehmernummer oder seiner Nutzergruppenzugehörigkeit, zu erlangen, wird sich
der Extbase-nativen Domain-Model-FrontendUser-Klasse bedient \cite{bib:typo3-ref-extbase-model-feuser}.
\pagebreak
Mit Abschluss der Phase der Digitization können alle Datenstrukturen im TYPO3-Backend händisch angelegt,
eingesehen, gelöscht und bearbeitet werden.
eingesehen, gelöscht, bearbeitet und im Frontend von Nutzern befüllt werden.
\section{Digitalization}
In der Phase \textit{Digitalization} werden bestehende Geschäftsprozesse so verändert,
@@ -435,7 +439,7 @@ Wird ein Wein als \enquote{eingegangen} markiert, wird der betroffene Teilnehmer
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 kommuniziert,
dass keine Änderungen vorgenommen wurden.
Abschließend werden im Frontend allgemeine Daten über den Wein angezeigt, damit sich Mitarbeiter sicher sein können,
Abschließend werden im Frontend allgemeine Daten zum Wein angezeigt, damit sich Mitarbeiter sicher sein können,
den richtigen Wein eingescanned zu haben.
\subsection{CSV-Export}
@@ -459,7 +463,7 @@ Das CSV-Dokument wird über die PHP-native Funktion \enquote{fputcsv} generiert.
numerisch indizierten Array und schreibt eine darauf basierende CSV-Zeile in eine Datei \cite{bib:php-fputcsv}.
Um gut wartbaren PHP-Code zu erzeugen, werden alle CSV-Zeilen in einem zweidimensionalen Array,
der das gesamte CSV-Dokument darstellt,
durch alphanumerisch indizierte, innere Arrays abgebildet. Somit ist bei jeder Wertzuweisung der zugehörige Spaltenname ersichtlich.
durch alphanumerisch indizierte, innere Arrays abgebildet. Somit ist bei jeder Wertzuweisung der zugehörige Spaltenname als Array-Key ersichtlich.
Über die nativen PHP-Funktionen \enquote{array\_keys} und \enquote{array\_values} wird dieser zwar gut lesbare,
aber mit \enquote{fputcsv} inkompatible
Array zu einer Reihe kompatibler Array konvertiert. Hierbei werden durch \enquote{array\_keys} die Kopfzeile und durch
@@ -471,12 +475,12 @@ Um \ac{WM} weitere Arbeitszeit zu ersparen, wird eine Download-Funktion für CSV
angeboten. Das erspart das manuelle Kopieren und Abspeichern von CSV-Zeichenketten durch IT-Fachfremde, reduziert damit die Anzahl
an benötigten Übergangsschritten in weitere Prozesse und reduziert somit die Komplexität der Umstellung.
Auch im Interesse, Arbeitszeit in der Umsetzung zu sparen,
wurde diese Downloadfunktion JavaScript-seitig umgesetzt.
wird diese Downloadfunktion javascript-seitig umgesetzt.
Dadurch ist der Download in derselben Action, die CSV für das Textarea-Feld generiert, implementiert.
Somit muss weder abstrahiert werden, noch ein weiterer CSV-Exporter gebaut werden.
Hierfür wird ein EventHandler auf den Download-Button angewandt, der bei Betätigung ein vestecktes
\enquote{a}-Element erstellt, über das HTML-Attribut \enquote{download} des \enquote{a}-Elementes den Download-Dateinamen
festlegt und als \enquote{href}-HTML-Attribut
eine Blob-URL zuweist. Diese Blob-URL wird über ein Blob-Objekt generiert.
Wird nun der Download-Button gedrückt, wird JavaScript-seitig eine Datei erzeugt und gespeichert
Wird nun der Download-Button gedrückt, wird javascript-seitig eine Datei erzeugt und gespeichert
\cite{bib:tutorialspoint-js-save-text}.