diff --git a/chapters/anforderungserfassung.tex b/chapters/anforderungserfassung.tex index a60aebc..1e9f1a0 100644 --- a/chapters/anforderungserfassung.tex +++ b/chapters/anforderungserfassung.tex @@ -121,5 +121,5 @@ Die wichtigsten Erkenntnisse des Interviews sind: \end{description} -Der Online-Fragebogen für teilnehmende Weingüter wurde über einen Monat hinweg nicht beantwortet -und ermittelte bis auf das Desinteresse der Stakeholdergruppe keine näheren Informationen. +Der Online-Fragebogen für teilnehmende Weingüter wurde über einen Monat hinweg nicht beantwortet, insofern +gibt es keine Ergebnisse zu präsentieren. diff --git a/chapters/konzeption-entwicklung.tex b/chapters/konzeption-entwicklung.tex index 61125f0..b894111 100644 --- a/chapters/konzeption-entwicklung.tex +++ b/chapters/konzeption-entwicklung.tex @@ -20,8 +20,8 @@ Spezifisch ist der \enquote{vergleichbare Funktionsumfang}, dass es Datenmodelle Frontendlogik in Bezug auf die zuvor genannten Datenmodelle gibt. \section{Digitization} -Die Phase der Digitazion 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:dougherty, bib:loebbecke}. +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}. Das bedeutet, dass in dieser Phase Datenobjekte definiert und implementiert werden. Ein Datenobjekt besteht nach firmeninternen Konventionen aus zumindest vier Komponenten: @@ -93,6 +93,12 @@ eingesehen, gelöscht und bearbeitet werden. \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. + \subsection{Teilnehmerregistrierung} Ein essenzieller Teil des Jahresauswahlprobenwerkzeuges ist die Registrierung von Teilnehmern. Dieses Modul repräsentiert den ersten Berührungspunkt der Winzer mit dem System. @@ -114,6 +120,8 @@ Nach erfolgreichem Login, wird ein Teilnehmerobjekt erstellt. Wählt der Nutzer \enquote{Nein, ich bin kein Mitglied} aus, würde er auf ein Registrierungsformular weitergeleitet, auf um sich einen Nicht-Mitgliederaccount 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}. \begin{nicepic} \includegraphics[width=0.9\textwidth]{images/ux-flow-registrierung.png} @@ -150,10 +158,11 @@ Stammdatenformular konfrontiert. Dabei handelt es sich um Angaben zum teilnehmen Wird dieses Formular abgeschickt, ist die Teilnehmerregistrierung abgeschlossen. \subsubsection*{Mitglied, mit Konto} -Ist ein Nutzer ein Mitglied und hat bereits ein Mitgliedskonto, muss dieser auf der Registrierungsseite +Ist ein Nutzer ein Weinland-Mosel-Mitglied und hat bereits ein Mitgliedskonto, muss dieser auf der Registrierungsseite \enquote{Ich bin ein Mitglied} auswählen. An dieser Stelle navigiert der Browser zu einem Login-Formular. -Hier kann sich das Mitglied nun anmelden. Tut er dies erfolgreich, ist die Teilnehmerregistrierung -abgeschlossen. +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. \subsubsection*{Mitglied, ohne Konto} Ist ein Nutzer ein Mitglied und hat noch kein Mitgliedskonto, muss dieser auf der Registrierungsseite @@ -163,12 +172,10 @@ Da der Nutzer noch keinen Account hat, muss dieser auf \enquote{Jetzt registrier 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. -Nach erfolgreichem Login wird das Mitgliedskonto um die notwendingen Teilnehmereigenschaften erweitert -und ist somit erfolgreich als Teilnehmer registriert. +freigegeben und es öffnet sich ein Login-Formular, beschrieben in \enpointy{Mitglied, mit Konto}. \subsubsection*{Umsetzung} -Um das umzusetzen wurde zunächst ein simples Weichen-Content-Element erstellt. +Zunächst wurde ein simples Weichen-Content-Element erstellt. 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}. Der Zweck dieses Content-Elementes ist es, Nutzer basierend auf einer ausformilierten Frage auf eine @@ -200,3 +207,119 @@ da diese Werte erst im Zuge der Persistierung erstellt werden. Das ist so, da da \enquote{AUTO\_INCREMENT}-Schlüsselwort lediglich zu SQL gehört und SQL nur von der Datenbank ausgeführt wird. Die Lösung hierfür ist es, beide Elemente zu erstellen und zu persistieren, danach ihre Uids gegenseitig 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. + +\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. +Das ist essenziell, da eine URL, auch wenn für sie keine Schaltfläche existiert, dennoch aufgerufen werden könnte. +Da Jahresauswahlprobennummern (uids) fortlaufend generiert werden, 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 +UIDs 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. +Rekursiv aufgerufene For-Schleifen, die sich selbst erneut für alle Elemente aufrufen, +können jedoch 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, +da es sich hierbei nicht um einen Divide-and-Conquer-Algorithmus handelt \cite{bib:schwarzer-vorlesung-alg}. +Das ist so, da das in der Rekursion weitergereichte Problem nicht kleiner wird, +sondern gleich groß bleibt. +Das verletzt die Bedingung $b>1$ des Master-Theorem, dargestellt als\\$T(n) = a*T(\frac{n}{b})+f(n)$. +Betrachten wir den Algortihmus, besteht er 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. +Grund dafür ist, dass Optgroup-Titel an sich nicht als Option 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 +Baumblättern und -Zweigen nicht ohne weiteres möglich ist. 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{} und den +Wert \enquote{-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 +Wert tragen, extrahiert werden. D.h., der Funktionsaufruf filtert alle Keys und somit alle Formfeld-IDs des Formfeldparameter-Arrays heraus, die den Wert \enquote{-true} haben. Das ist eine Liste +aller Formfeld-IDs der Checkboxen des SelectMultiples, die angehakt wurden. +Mit der eingebauten PHP-Funktion \enquote{array\_map} wenden wir nun eine Operation auf alle Schlüssel +der Liste an, 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 UIDs 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. diff --git a/chapters/stand-der-forschung.tex b/chapters/stand-der-forschung.tex index a95bcb8..2a14688 100644 --- a/chapters/stand-der-forschung.tex +++ b/chapters/stand-der-forschung.tex @@ -65,13 +65,12 @@ werden \cite{bib:Parviainen_Tihinen_Kaariainen_Teppola_2022}. Nach Verhoef et al. lässt sich der hier sogenannte \enquote{Prozess der Digitalisierung} in drei Phasen unterteilen. Diese drei Phasen sind \textit{Digitization}, \textit{Digitalization} und \textit{Digital Transformation} \cite{bib:verhoef}. - Die Phase \textit{Digitization} befasst sich mit der Umwandlung analoger Datenstrukturen und Modellen in digitale Datenmodelle, -sodass diese digital, z.B. in Form von Nullen und Einsen, gespeichert und elektronisch weiterverarbeitet werden können +sodass diese digital, in Form von Nullen und Einsen, gespeichert und elektronisch weiterverarbeitet werden können \cite{bib:dougherty, bib:loebbecke}. \textit{Digitalization} beschreibt den Prozess der Veränderung bestehender Geschäftsprozesse, um mit digitalen Werkzeugen und Datenmodellen zu arbeiten \cite{bib:fengli}. -Die letzte Phase, die \textit{Digitale Transformation} beschreibt eine firmenweite Veränderung, die beispielsweise +Die letzte Phase, die \textit{Digitale Transformation}, beschreibt eine firmenweite Veränderung, die beispielsweise Ergründungen neuer Geschäftsmodelle mit sich bringen könnte \cite{bib:pagani}. \section{Abwägung in Bezug auf die Problemstellung} diff --git a/dexes/acrodex.tex b/dexes/acrodex.tex index 547b029..24f6d60 100644 --- a/dexes/acrodex.tex +++ b/dexes/acrodex.tex @@ -30,6 +30,9 @@ \acro{PO}[PO]{Product Owner} \acroplural{PO}[POs]{Product Owner} + +\acro{UID}[UID]{Uinique Identifier} +\acro{PID}[PID]{Parent Identifier} % % \end{acronym} diff --git a/dexes/literature.bib b/dexes/literature.bib index 01e8815..4a6efd2 100644 --- a/dexes/literature.bib +++ b/dexes/literature.bib @@ -19,6 +19,13 @@ publisher = {Hochschule Worms}, } +@book{bib:schwarzer-vorlesung-alg, + author = {Volker Schwarzer}, + title = {Vorlesung: Algorithmen und Datenstrukturen}, + year = {2022}, + publisher = {Hochschule Worms}, +} + @article{bib:Parviainen_Tihinen_Kaariainen_Teppola_2022, title={Tackling the digitalization challenge: how to benefit from digitalization in practice}, volume={5}, @@ -320,6 +327,22 @@ note = {Zugriff: März 2023} } +@misc{bib:w3schools-input, + author = {{W3Schools}}, + howpublished = "\url{https://www.w3schools.com/tags/tag_input.asp}", + title = {{HTML Tag}}, + year = {2023}, + note = {Zugriff: März 2023} +} + +@misc{bib:typo3-fluid, + author = {{TYPO3 Association}}, + howpublished = "\url{https://typo3.org/fluid}", + title = {{Fluid - A fast and secure templating engine}}, + year = {2023}, + note = {Zugriff: März 2023} +} + @misc{bib:typo3-docs-managing-extensions, author = {{TYPO3 Contributors}}, howpublished = "\url{https://docs.typo3.org/m/typo3/tutorial-getting-started/main/en-us/Extensions/Management.html}", @@ -407,3 +430,11 @@ year = {2023}, note = {Zugriff: März 2023} } + +@misc{bib:typo3-docs-fluid-form-viewhelpers, + author = {{TYPO3 Contributors}}, + howpublished = "\url{https://docs.typo3.org/other/typo3/view-helper-reference/11.5/en-us/typo3/fluid/latest/Form/Index.html}", + title = {{form - Fluid ViewHelper Reference 11.5 Documentation}}, + year = {2023}, + note = {Zugriff: März 2023} +} diff --git a/images/timecomplexity-category.png b/images/timecomplexity-category.png new file mode 100644 index 0000000..7e4dd44 Binary files /dev/null and b/images/timecomplexity-category.png differ diff --git a/main.pdf b/main.pdf index 139ec46..0171fa3 100644 Binary files a/main.pdf and b/main.pdf differ diff --git a/test.php b/test.php new file mode 100644 index 0000000..c11d940 --- /dev/null +++ b/test.php @@ -0,0 +1,45 @@ + $i+1, + 'parent' => rand(0, $i) + ]; + } + + $before = hrtime()[1]; + T($arr, 0); + $after = hrtime()[1]; + + $delta = $after - $before; + + return $delta; +} + +function testAvg($numItems, $numRuns) { + $execTimes = []; + for ($i = 0; $i < $numRuns; $i++) { + $execTimes[] = testOne($numItems); + } + + sort($execTimes); + $med = round($execTimes[count($execTimes)/2] / 4206040); + + #echo("$numItems took on average $med time units. ($numRuns sample size)\n"); + echo("($numItems, $med)\n"); +} + +for ($i = 0; $i <= 5000; $i += 100) { + testAvg($i, 10); +}