Dokumentation
Betriebsbedingungen
Wenn die HTML Dateien vom lokalen Dateisystem geöffnet werden, können Layout, Navigation, Header und Footer nicht geladen werden. Für den reibungslosen Betrieb wird daher eine XAMP-Installation empfohlen. Die Seite wurde hauptsächlich im Firefox getestet, daher kann die Funktionalität in anderen Browsern nicht garantiert werden.
Client
- Aktueller Browser (getestet mit Firefox)
Infrastruktur
Standard
- Apache 2.4 Webserver
- PHP 8.0
- MariaDB 10.4 (localhost)
- DB User: "root" (create/read/write Berechtigungen)
- DB Passwort: ""
- Leeres Schema: "test"
Das Aufrufen von Tabellen erzeugen und füllen (src/resources/pages/feed/tables-create.php) erzeugt die erforderlichen Datenbanktabellen "post" und "comment" in dem Schema "test".
1. Alternative mit XAMPP
- XAMPP 8
- DB User: "root" (create/read/write Berechtigungen)
- DB Passwort: ""
- Leeres Schema: "test"
2. Alternative mit Docker
- Linux-Betriebssystem verwenden
- Docker installieren: curl https://get.docker.com | bash
- Container starten: ./run.sh
Gundlegender Aufbau
Ordnerstruktur
Die obersten Ebene ist für die Hauptseiten reserviert. Für jede Seite liegt dort eine Datei, die die HTML-Elemente mit dem Inhalt enthält. Neben den Dateien liegt der Ordner "resources", in dem alle weiteren benötigten Dateien sind.
- "components" - Hier liegt HTML Code, der dynamisch in mehrere Seiten eingebettet wird.
- "components/nav" - Die Unterordner und Dateinamen entsprechen immer dem HTML-Tag. Z.B. Inhalt für den "nav"-Tag liegt in "components/nav/nav.php"
- "shared" - Dateien die auf mehreren Seiten eingebunden werden, liegen im Ordner shared.
- "shared/fonts" - Schriftarten die nicht vorinstalliert oder extern eingebunden sind liegen hier.
- "shared/style" - Dies ist der Ordner für die gemeinsamen CSS-Dateien.
- "pages" - Im "pages"-Ordner liegen die Dateien, die nur auf einer Seite benötigt werden. Die Namen der Unterordner entsprechen immer dem Name der Seite.
- "pages/paint" - Alle Dateien, die zu "paint.php" gehören liegen im Ordner "paint".
Komponenten
Damit die Navigation und der Footer nicht auf jeder Seite als Duplikat vorhanden ist, werden diese Komponenten ausgelagert. Auf den Seiten müssen nur per php include (Z.B. mit "<?php include 'resources/components/nav/nav.php'; ?>" ) die passenden Bereiche eingebunden sein. Die eingebundene PHP-Datei enthält dann die Inhalte des entsprechenden Tags. Somit muss die Navigation bei Änderungen nur an einem Ort geändert werden. Scripte die nur auf einer Seite vorhanden sein sollen, können auf der jeweiligen Seite unterhalb des includes definiert sein. Scripte die auf jeder Seite vorhanden sein sollen, werden in die PHP-Datei eingefügt, die von allen Seiten verwendet wird.
HTML-Struktur
Für die Aufteilung in einzelne Bereiche habe ich die modernen HTML5-Elemente statt divs verwendet. Durch diese Tags können die Browser die Seite einfacher für alternative Darstellungen aufbereiten, da sie die Inhalte so besser zuordnen und priorisieren können.
Grundstruktur:
Oben wird der Header mit Logo angezeigt, links die Navigation und den restlichen Platz nimmt das Main-Element ein. Der Footer ist innerhalb von Main, am Ende des Inhalts.
Inhalte werden so dargestellt:
Seiten
Startseite, index.php
Diese Seite zeigt nur einen einfachen Text an. Diese Seite ist der Einstiegspunkt.
Bei einer Anfrage ohne Angabe einer Datei, sucht der Webserver nach Dateien mit dem Name "index" und liefert diese aus.
Scroll Demo, scroll.php
Auf der "Scroll Demo"-Seite habe ich Platzhaltertext eingefügt, um den statischen Header, der in die Seitenleiste übergeht, zu demonstrieren.
Hier ist auch das mehrspaltige Layout umgesetzt, das ich unter der Überschrift "Flexbox" genauer erläutere.
Paint, paint.php
Mit dem Knopf "Line" wird das Linientool ausgewählt. Dieses zeichnet eine gerade Linie von dem Ort, an dem die Maustaste gedrückt wird bis zum Ort, an dem die Taste losgelassen wird.
Mit dem "Circle"- Werkzeug kann man einen Kreis zeichnen. Der Mittelpunkt des Kreises liegt dort wo die Maustaste gedrückt wird. Durch Bewegen der Maus Horizontal oder Vertikal wärend dem Klick kann der Radius festgelegt werden.
"Clear" leert die Leinwand und wählt das Line-Tool aus.
Feed, feed.php
Diese Seite demonstriert die Funktionsweise von PHP und Formularen. Auf der Seite können Beiträge hinzugefügt und kommentiert werden.
Dokumentation, dokumentation.php
Auf dieser Seite werden mehrere Schriften mit verschiedenen Schriftschnitten für Inhalt und Überschrifen verwendet.
z.B. wird mit "font-family: Consolas; die Haupt-Überschrift (h1) auf Consolas festgelegt. Durch Angabe von weiteren Schriften, durch Komata getrennt, können Fallback-Schriften angegeben werden. Diese werden dann verwendet wenn die angegebene Schriftart nicht auf dem Zielrechner vorhanden ist.
Die Schrift-Fabe kann mit "color: #5555" geändert werden. Der Schriftschnitt z.B. mit "font-style: italic".
Layout
CSS Grid
Damit ich für das Layout nicht mit float, Tabellen oder ähnlichem arbeiten muss, habe ich mich für das CSS Grid Layout entschieden. Dies ist eine relativ neue CSS Funktion, die außer im Internet-Explorer in allen aktuellen Browsern funktioniert. Mit CSS Grid kann im Elternelement einfach die Breite von allen Spalten angegeben werden; bei mir 17rem für die Seitenleiste und den restlichen Platz für den Inhalt. Mit grid-template-areas kann dann ganz intuitiv definiert werden welche Bereiche von der Website an welche Position gehören und über wie viele Zeilen/Spalten sie sich strecken sollen.
1rem = Schriftgröße des Browser
Über grid-area wird dann ein div oder ein anderes HTML-Element einem Bereich zugeordnet.
Hier habe ich z.B. das header-Element dem Bereich header zugeordnet:
Code: main.css
Quelle: developer.mozilla.org
Flexbox
CSS Grid fokusiert sich auf das Layouting der Seite, also dem aufteilen der Seite auf mehrere Bereiche. Flexbox hingegen ist für das Layouting von Inhalten konzipiert.
Ich habe eine CSS-Klasse split-layout definiert, die an Section-Elemente im Main-Abschnitt angehängt werden kann. Damit werden dann alle Kinder in der Section gleichmäßig nebeneinander angeordnet. Wenn nicht alle Elemente nebeneinander passen, werden die Restlichen in einer neuen Zeile platziert.
">" bedeutet nur direkt darin enthaltene Elemente werden selektiert. Elemente die weiter innen in der Verschachtelung liegen sind nicht betroffen.
"*" bedeutet jedes Element.
"xxx > *" selectiert also jedes direkt in xxx liegende Element.

Der CSS Selector "main section.split-layout" Selectiert alle section-Elemente mit der Klasse "split-layout" im Container Main.
Durch den Befehl display: flex werden alle Kind-Elemente in dem Eltern-Element(section) vom Browser automatisch angeordnet.
Der CSS Selector "main section.split-layout > *" Selectiert alle direkt darin liegenden Kind-Elemente.
Standardmäßig ist die Größe dieser Kind-Elemente abhängig von der Inhaltsmenge. So wären diese Kind-Elemente bei unterschiedlicher Textlänge unterschiedlich Breit.
Um das zu verhindern, habe ich mit dem Befehl flex-basis: 10% dem Browser mitgeteilt, dass die Kind-Elemente initial mit einer Größe von 10% angelegt werden sollen. Dadurch starten alle Elemente mit der gleichen Größe und freier Platz wird gleichmäßig auf die Elemente aufgeteilt.
Damit die article-Elemente, die ich nebeneinander anordne, nicht direkt zusammenstoßen, habe ich jeweils einen Abstand von 1em dazwischen eingefügt.
Ich selectiere alle article-Elemente, die in einer solchen "split-layout" liegen, und füge rechts einen Abstand hinzu. Das letzte Element der article-Zeile braucht keinen solchen Abstand, weil Rechts die Seite aufhört. Durch die Pseudoklassen :not und :last-of-type wird der margin nicht auf das letzte Element angewendet.
Code: main.css
Quelle: css-tricks.com
Techiken
JavaScript
Mit HTML-Elementen interagieren
Mit "document.getElementById("canvas")" wird das Element mit der id "canvas" selektiert. Damit stehen dann verschiedene Funktionen des Elements zur Verfügung. Zum Beispiel die Funktion "addEventListener("mousedown", mousedown)", mit der ich einen Eventlistener an das Element hänge um die Mausevents zu verwenden.Mit "canvas.getBoundingClientRect()" bekomme ich den Offset, den das Canvas-Element zur linken oberen inneren-Ecke des Browsers hat. Damit kann dann die Position der Maus auf dem Canvas berechnet werden.
Quelle: stackoverflow.com
Aktiven Menüpunkt makieren
Weil ich die Navigation per php einfüge, wird kein Menüpunkt im HTML hervorgehoben. Um trozdem die aktuelle Seite im Menü hervorzuheben, habe ich JavaScript verwendet.
Mit "Element.classList.add("active")" wird dem Aktiven Menüpunkt eine Klasse angehängt, die ihn dann hervorhebt.
Code: components.js
Quelle: Den Code in der Funktion markActiveLink() habe ich von w3schools.com übernommen und abgewandelt.
Eigene Klassen
Für die Programmierung der Paint Anwendung habe ich JavaScript-Klassen verwendet, die im "ECMAScript 6"-Standard definiert sind.
Die Klassen LineTool und CircleTool haben beide die gleichen Funktionen. Nur die Implementierung der draw() Funktion unterscheidet sich.
Da der Aufruf der Tools sich nicht unterscheidet, können neue Tools einfach hinzugefügt werden. Dazu benötigt man lediglich eine neue Klasse für das Tool und einen neuen Button in dem das Objekt erzeugt wird. Der restliche Code bleibt unverändert.
Verwendung:
Code: paint.js
Quelle: w3schools.com
PHP
Mit PHP habe ich eine kleine Anwendung zum erstellen und kommentieren von Beiträgen geschrieben. Diese ist auf der Unterseite "Feed" erreichbar. In der Datei "src/resources/pages/feed/application/domain/Comment.php" habe ich eine PHP Klasse für ein Kommentar. In "src/resources/pages/feed/application/usecase/AddComment.php" befindet sich Code, der diese Klasse verwendet. Dort wird ein neues Kommentar-Objekt erzeugt und mit dem Repository-Pattern persistiert. Die gespeicherten Daten werden in der Datei "src/resources/pages/feed/render-post.php" ausgelesen und verwendet. Ausgeführt wird diese Datei zum Beispiel beim Aufrufen von feed.php?type=post&id=2Eine PHP-Klasse mit einem Attribut und Konstruktor ist so aufgebaut:
Datenbank
Zugriff von PHP
Für die Datenbankverbindung habe ich mir eine Hilfsklasse "DBConnection" geschrieben.Diese stellt mit "mysqli_connect($this->hostname, $this->username, $this->password, $this->dbname)" eine Verbindung zur Datenbank her.
Mit "mysqli_query($this->db, $sqlquery)" und "mysqli_fetch_array($query)" können die SQL-Befehle ausgeführt bzw. die Daten abgefragt werden.
Code: src/resources/pages/feed/application/infrastructure/DBConnection.php
Tabellenstruktur
Für die Feed Application habe ich die 2 Tabellen "post" und "comment" definiert.
SQL-Befehle
Hinweis: Die SQL-Statements sind zur Anschaulichkeit verkürzt und passen daher nicht immer zu der abgebildeten Tabellenstruktur.Mit dem Befehl "CREATE TABLE 'test'.'post'" wird eine neue Tabelle "post" in dem Schema "test" erstellt:
- "AUTO_INCREMENT" füllt das Feld automatisch mit dem nächsten Wert, wenn kein Wert angegeben wurde.
- "PRIMARY KEY (`id`)" markiert die Spalte "id" als Primärschlüssel.
- "NOT NULL" legt fest, dass das Feld nicht leer sein darf.
Mit dem Befehl "INSERT" kann ein Eintrag zu einer Tabelle hinzugefügt werden:
Mit dem Befehl "UPDATE" wird ein Eintrag in der Tabelle aktualisiert:
- Mit "WHERE" wird gefiltert, welche Einträge aktualisiert werden sollen. (Hier ist es nur ein Eintrag, weil die Spalte ID einen einen Eintrag eindeutig identifiziert.)
Die Tabellen "post" und "comment" sind über die Spalte "comment.post_id" verknüpft.
Mit "JOIN" können somit alle Kommentare inclusive dem zugehörigen Post-Content angezeigt werden:
Code: src/resources/pages/feed/application/usecase/AddExamples.php
Code: src/resources/pages/feed/application/infrastructure/PostRepository.php
Canvas
Zeichnen
Mit "getContext("2d")" wird dem Canvas signalisiert, dass 2D-Zeichnungen erstellt werden soll. Dieses 2D Canvas-Objekt wird dann zurückgegeben damit man damit interagieren kann. Die verwendeten Funktionen sind unten erklärt.beginPath()
Startet eine neue Zeichnung auf dem Canvas. D.h. vorherige move-Anweisungen werden zurückgesetzt.moveTo(x, y)
Bewegt den virtuellen Pinsel an übergebene Position.lineTo(x, y)
Zeichnet die Linie von der aktuellen Pinselposition zu der übergebenen Position.strokeStyle = color
Hiermit kann die Farbe festgelegt werden. Z.B. "#000000" für Schwarz.stroke()
Führt die angegebenen Path-Anweisungen endgültig aus und wendet es auf das Canvas an, so dass es sichtbar ist.Nutzereingabe
Siehe Abschnitt JavaScript.Code: paint.js
Quelle: Canvas-Arbeitsblatt