5. Einrichtung der Backend-Logik
Die Implementierung der Backend-Logik wird der komplexeste Schritt sein. Es wird darum gehen, die API-Endpunkte für Frontend-Komponenten bereitzustellen und die Backend-Logik für Übungserstellung, -änderung, -durchführung und -bewertung zu implementieren.
Es kann natürlich auch erst mit der Ausgestaltung der Frontend-Komponenten begonnen werden, jedoch wird hier der Übersichtlichkeit halber ein Back-to-Front-Ansatz vorgestellt.
Die Übungsmodule werden an die sogenannte UebungenAPI im Hermeneus-Core angeschlossen, die als zentraler Mittelsmann zwischen einzelnen Übungsmodulen und dem Hermeneus-Core fungiert.
5.1 Die UebungenAPI
Die Backend-Entwicklung wird durch die sogenannte UebungenAPI erleichtert, die dem Entwickler einige Aufgaben abnimmt, indem sie:
- Standardisierte API-Routes für CREATE, READ, UPDATE, DELETE-Operationen vordefiniert.
- Standardisierte Datenstrukturen von diesen API-Routes ans Frontend zurückgibt, aber auch standardisierte Datenstrukturen vom Entwickler einfordert.
- Automatische Validierung von Nutzereingaben vornehmen kann.
- Standardisierte Methodennamen vorgibt, in denen die jeweilige Übungslogik implementiert werden muss.
5.2 Wichtiges Vorwissen
5.2.1 UebungenAPI-Routes vs. Web-Routes
Bei den Routes gibt es eine wichtige Unterscheidung zu treffen zwischen den API-Routes, die bereits standardmäßig von UebungenAPI bereitgestellt werden und den Web-Routes der Übung, die der Entwickler selbst definieren muss.
| Aspekt | UebungenAPI-Routes | Web-Routes |
|---|---|---|
| Lokalisierung | /routes/uebungen/uebungen.api.php | /modules/Uebungen/UebungVokabeltrainer/routes/uebung-vokabeltrainer.web.php |
| Definition | Vom Hermeneus-Core vorgegeben | Vom Modulentwickler definiert |
| Einsatzzweck | Stellen Daten für die entsprechenden Operationen bereit, die dann von den entsprechenden Frontend-Komponenten verarbeitet, geparst usw. werden | Führen den Nutzer zu der entsprechenden Operation eines Übungsmoduls (z.B. Druckansicht, Übungsbearbeitung, ...) |
| Rückgabewerte | Geben Daten in Form einer vordefinierten JSON-Response zurück | Möglich sind die Rückgabe reiner Daten, die Rückgabe von Blade-Views, die Weiterleitung zu anderen Web-Routes usw. |
Der Entwickler kann optionalerweise im Routes-Verzeichnis des Moduls noch zwei weitere Routes-Files mit anderen Zwecken anlegen:
/modules/Uebungen/UebungVokabeltrainer/routes/uebung-vokabeltrainer.core.php- Definieren von Routes, dann ohne das Präfixuebungen/uebung-activitas/registriert werden./modules/Uebungen/UebungVokabeltrainer/routes/uebung-vokabeltrainer.api.php- Definieren von modulspezifischen API-Routes, die dann mit dem Präfixapi/uebungen/uebung-activitas/registriert werden.
5.2.1 Die Methoden im Übung-Model
Das Übung-Model (in unserem Fall /modules/Uebungen/UebungVokabeltrainer/app/Models/UebungVokabeltrainer.php) erweitert die Klasse UebungBase und ist dadurch gezwungen, die folgenden Methoden zu implementieren:
storeUebung(): Erstellen einer neuen Übung in der Datenbank.updateUebung(): Aktualisieren einer bestehenden Übung in der Datenbank.deleteUebung(): Löschen einer bestehenden Übung in der Datenbank.printUebung(): Druckfunktion einer Übung.shareUebung(): Eine Übung per Tessera teilen: Es wird eine Tessera angelegt, die auf dieabsolve-Route der Übung verweist.showUebung(): Anzeigen einer bestehenden Übung.previewUebung(): Vorschau einer bestehenden Übung.absolveUebung(): Eine Übung durchführen.evaluateUebung(): Übung aus- und bewerten. Ggf. Gravitaspunkte verleihen und Feedback anzeigen.
Die Operationen showUebung(), und absolveUebung() sind im Grunde gleich, da die Daten zur Anzeige/Durchführung der Übung nötig sind, angefordert werden. Gleiches gilt für printUebung() und previewUebung(), jedoch kann es sein, dass man hier für jeden Einsatzzweck andere Daten zurückgeben möchte.
5.2 Implementierung der CREATE-Logik: Persistierung einer neu erstellten Übung in der Datenbank
5.2.1 Das Szenario
Ein Nutzer erstellt eine neue Übung vom Typ uebung-vokabeltrainer, die später anderen Nutzern zur Verfügung gestellt werden soll. Von einer künftigen Frontend-Komponente sollen folgende Daten per POST-Request (über den Axios-Wrapper haxios.js) an einen CREATE-Endpunkt weitergegeben werden:
{
"data": {
"title": "Neue Vokabelübung",
"description": "Tippe die richtige Bedeutung ein!",
"content_data": {
"value_given": "laudare",
"value_expected": "loben, rühmen",
}
},
"some_other_data": {
"log_info": "Ein neues Vokabelübungsmodul wurde erstellt."
}
}Wichtige Hinweise:
- Die drei Felder
title,descriptionundcontent_datawurden bereits vorab in der Konfigurationsdateiconfig.jsondefiniert. - Für die
UebungenAPImüssen alle Felder unseres Übungsmoduls unter einemdata-Objekt übertragen werden. some_other_datawurde nicht in der Konfigurationsdatei hinterlegt. Es ist aber möglich außerhalb desdata-Objekts weitere Daten anzugeben, die später dennoch bei der CREATE-Logik zur Verfügung stehen (wenn man beispielsweise neben der reinen CREATE-Operation noch eine weitere Operation mit separaten Daten durchführen lassen möchte.)
5.2.2 Welche Route brauche ich für die CREATE- bzw. store-Operation?
Die UebungenAPI stellt bereits standardisierte API-Routes bereit, die unter routes/uebungen/uebungen.api.php einsehbar sind. Sie können ebenfalls mit dem Artisan-Command php artisan route:list angezeigt werden (im /api/-Bereich).
Die gesuchte Route ist:
// POST
`/api/uebungen/store/{alias}`oder in unserem Beispiel:
// POST
`/api/uebungen/store/uebung-vokabeltrainer`5.2.3 Wo führe ich die CREATE- bzw. store-Operation aus?
Wird ein Request mit den oben definierten Daten an die o.g. Route geschickt, werden die im data-Objekt enthaltenen Daten automatisch durch die UebungenAPI validiert (falls aktiviert) und an die Methode storeUebung des Models in unserem Übungsmodul zur Verarbeitung weitergegeben.
In /modules/Uebungen/UebungVokabeltrainer/app/Models/UebungVokabeltrainer.php:
public function storeUebung(array $data, Request $request = null): static
{
// Hier können Daten verändert werden usw...
$data['content_data'] = UebungVokabeltrainer::manipulateContentDataOrWhatever($data['content_data']);
$NeueUebungVokabeltrainer = new UebungVokabeltrainer($data);
$NeueUebungVokabeltrainer->save();
// Hier kann das weitere Feld `some_other_data` verarbeitet werden.
// Diese Request-Daten sind allerdings nicht durch die `UebungenAPI` validiert worden.
Log::info($request->input('some_other_data.log_info'));
return $NeueUebungVokabeltrainer;
}5.2.4 Was genau kommt von der CREATE- bzw. store-Route als Antwort zurück?
Die UebungenAPI kapselt den Rückgabewert von storeUebung() und gibt sie im data-Feld eines standardisierten JSON-Response-Objektes wieder ans Frontend zurück. Dieses hat folgende Struktur:
{
"data": {
"uebung": {
// ... Rückgabewert von `storeUebung()`
}
},
"errors": [
// ... Mögliche Fehlermeldungen
],
"messages": [
"Die Übung wurde erfolgreich erstellt."
],
"status": {
// ... HTTP-Statuscode
}
}5.2.5 Kann ich auch benutzerdefinierte Daten in dieser JSON-Response zurückgeben?
Ja, sofern die Methode storeUebungResponseData() im entsprechenden Übungs-Model definiert ist.
In /modules/Uebungen/UebungVokabeltrainer/app/Models/UebungVokabeltrainer.php:
/**
* In dieser Methode können zusätzliche Daten hinterlegt werden, die die CREATE-Route der ÜbungenAPI zurückgibt.
* Wenn diese Methode im Model hinterlegt ist, werden die Standard-Daten,
* die von der CREATE-Route zurückgegeben werden, überschrieben.
* @param Request|null $request
* @return UebungenAPICustomData
*/
public function storeUebungResponseData(Request $request = null): UebungenAPICustomData
{
return new UebungenAPICustomData(
customData: [
'custom_data1' => 'Ein zusätzlicher Datenstring',
'custom_data2' => ['Ein', 'zusätzlicher', 'Datenarray']
],
errors: [],
messages: [
'Es wurde außerdem ein Log-Eintrag erstellt.'
]
);
}Dies würde folgende JSON-Response als Rückgabe erzeugen:
{
"data": {
"uebung": {
// ... Rückgabewert von `storeUebung()`
},
"custom": {
"custom_data1" : "Ein zusätzlicher Datenstring",
"custom_data2" : ["Ein", "zusätzlicher", "Datenarray"]
}
},
"errors": [
// ... Mögliche Fehlermeldungen
],
"messages": [
"Die Übung wurde erfolgreich erstellt.",
"Es wurde außerdem ein Log-Eintrag erstellt."
],
"status": {
// ... HTTP-Statuscode
}
}5.3 Einrichtung der UPDATE-Funktionalität
Damit Übungsdaten geändert werden können, muss ein Request an folgende Route der UebungenAPI geschickt werden. Aus dem Frontend geschieht dies bestenfalls wieder mit dem Axios-Wrapper haxios.js: Update-Route: POST /api/uebungen/update/uebung-vokabeltrainer
Alle Daten innerhalb des data-Objekts werden durch die UebungenAPI validiert.
In /modules/Uebungen/UebungVokabeltrainer/app/Models/UebungVokabeltrainer.php kann jetzt die UPDATE-Logik implementiert werden:
public function updateUebung(array $data, Request $request = null): static
{
$this->update([
'updated_attribute' => $data['updated_attribute_value']
// ...
]);
return $this;
}Wie in der STORE-Operation wird durch die UebungenAPI wieder eine entsprechende JSON-Response erzeugt (s.o.) Optional können weitere Daten bzw. Rückmeldungen mit updateUebungResponseData() hinterlegt werden.
5.4 Einrichtung der DELETE-Funktionalität
Damit eine Übung gelöscht werden kann, muss ein Request an folgende Route der UebungenAPI geschickt werden. Post-Route: POST /api/uebungen/delete/uebung-vokabeltrainer Normalerweise erfolgt die Löschung einer Übung durch die UebungenLibrary-Frontend-Komponente, in der die Frontend-Funktionalität zur Löschung schon eingerichtet ist. Es bleibt übrig, die Backend-Logik in unserem Übung-Model zu implementieren:
public function deleteUebung(Request $request = null): static
{
$this->delete();
return $this;
}Mit der Methode deleteUebungResponseData() kann die UebungenAPI wieder eine zusätzliche JSON-Response erzeugen.
5.2 Einrichtung der SHARE-Funktionalität
Damit wird gewährleistet, dass eine Tessera für diese Übung angelegt wird und diese per Tessera geteilt werden kann.
Die SHARE-Funktionalität ist in wenigen Schritten umsetzbar.
5.2.1 Shareable-Trait einbinden
In unserem Übungs-Model muss der Shareable-Trait eingebunden werden:
In /modules/Uebungen/UebungVokabeltrainer/app/Models/UebungVokabeltrainer.php:
use App\Traits\Shareable;
class UebungVokabeltrainer extends \App\Models\UebungBase {
use Shareable;
}Jetzt haben wir Zugriff auf die share()-Methode.
5.2.2 Einbinden der share()-Methode
In unserem Übungs-Model UebungVokabeltrainer.php müsste die Methode shareUebung() bereits vorhanden sein. Hier kann die share()-Methode eingebunden werden:
/**
* Wenn die Übung geteilt werden soll, wird diese Funktion aufgerufen
* Achtung: Hierzu muss der Shareable-Trait eingebunden werden.
* Die Methode `share()` des Traits erstellt eine neue Tessera
* und gibt diese auch wieder zurück.
* @param Request|null $request
* @return mixed
*/
public function shareUebung(Request $request = null): mixed
{
$UebungVokabeltrainerTessera = $this->share();
return $UebungVokabeltrainerTessera;
}Die Tessera wird im Response-Body der UebungenAPI wieder zurückgegeben, damit diese dem Nutzer z.B. in einer Frontend-Komponente angezeigt werden kann.
5.2.3 Einrichtung der WEB-Route, zu der die Tessera führt
Wir beabsichtigen, dass die Tessera zu der Route führt, die zur Durchführung der Übung verwendet wird. Was genau diese Route zurückgibt, entscheidet dann der Entwickler. In der Regel ist dies ein Blade-View, der eine Komponente zur Durchführung der Übung beinhaltet.
Damit dies funktioniert, müssen wir eine Named Route nach einem bestimmten Schema in der Dot-Notation einrichten. Diese richten wir in der Routes-file unseres Übungsmoduls ein: In /modules/Uebungen/UebungVokabeltrainer/routes/uebungen/uebungen.web.php:
use Illuminate\Support\Facades\Route;
use Modules\Uebungen\UebungVokabeltrainer\app\Controllers\UebungVokabeltrainerWebController;
Route::get('/absolve/{id}', [UebungVokabeltrainerWebController::class, 'absolve'])
->middleware('verified')
->name('uebungen.uebung-vokabeltrainer.absolve'); // Einrichtung der Named RouteDabei muss uebung-vokabeltrainer der Alias des Übungsmoduls sein.
Im UebungVokabeltrainerWebController wird die absolve-Methode über einen Trait eingebunden (App\ServiceClasses\Uebungen\UebungenAPI\Traits\ControllerTraits\showsAbsolveView), der automatisch einen Blade-View mit der Absolve-Übungskomponente zurückgibt. Falls eine eigene Logik zur Anzeige der Absolve-Komponent implementiert werden soll, kann man im Controller einfach den Trait überschreiben, indem man eine eigene absolve-Methode einfügt.