Verweissystem des Glossariums
Inhaltsverzeichnis
- Übersicht
- Datenmodell
- Verweis-Model
- Verweis-Typen (Relationen)
- Formverweise
- Alternativformen: Zwei Ansätze
- Accessor-Methoden in Vocab
- hasVerweise-Trait
- Polymorphe Beziehungen
- Verwendungsbeispiele
- Verwechslungsgefahr (confusion_factor)
- Verwendung in der Applikation
- Best Practices
Übersicht
Was ist das Verweissystem?
Das Verweissystem des Glossariums ermöglicht die Abbildung von Beziehungen zwischen lateinischen Lemmata. Es dient dazu, semantische, etymologische oder morphologische Verbindungen zwischen Vokabeln strukturiert zu speichern und in Übungen sowie bei der Textanalyse zu nutzen.
Zweck und Anwendungsfälle
Das Verweissystem wird verwendet für:
- Etymologische Beziehungen: Verwandte Wörter verknüpfen (z.B. venire und convenire)
- Synonyme und semantische Beziehungen: Ähnliche Bedeutungen verbinden
- Alternativformen: Verschiedene gültige Formen eines Wortes referenzieren
- Verwechslungsgefahr: Häufig verwechselte Wörter für Übungen markieren
- Kompositabeziehungen: Zusammengesetzte Wörter und ihre Bestandteile verknüpfen
- Lemmaverweis: Alternative Lemma-Formen (z.B. archaische Formen)
- Formspezifische Verweise: Besondere Formen eines Wortes auf andere Lemmata verweisen lassen
Verweis vs. Inline-Alternativform
Es gibt zwei grundlegende Ansätze zur Abbildung von Alternativformen:
1. Verweis-Eintrag (Datenbank)
- Strukturiert, abfragbar, filterfähig
- Ermöglicht Metadaten (Relation, Verwechslungsgefahr)
- Ideal für semantische Beziehungen
- Performanter bei vielen Verweisen
2. Inline im JSON (morph-Feld)
- Direkt in der Morphologie gespeichert
- Schneller Zugriff ohne JOIN
- Ideal für reine Formvarianten ohne semantische Bedeutung
- Beispiel:
"coepi / incepi"
Die Wahl hängt vom Use Case ab (siehe Abschnitt 6).
Datenmodell
Verweis-Tabelle (verweise)
Die Tabelle verweise speichert alle Verweisbeziehungen zwischen Vokabeln.
Tabellenstruktur
CREATE TABLE verweise (
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
from_vocab_id BIGINT UNSIGNED NOT NULL,
from_vocab_type VARCHAR(255) NOT NULL,
to_vocab_id BIGINT UNSIGNED NOT NULL,
to_vocab_type VARCHAR(255) NOT NULL,
form_from VARCHAR(255) NULL,
form_to VARCHAR(255) NULL,
relation VARCHAR(50) NULL,
confusion_factor FLOAT NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
deleted_at TIMESTAMP NULL
);Felderbeschreibung
| Feld | Typ | Nullable | Beschreibung |
|---|---|---|---|
id | BIGINT UNSIGNED | Nein | Primärschlüssel, Auto-Increment |
from_vocab_id | BIGINT UNSIGNED | Nein | ID des Quell-Lemmas (von wo der Verweis ausgeht) |
from_vocab_type | VARCHAR(255) | Nein | Vollständige Model-Klasse des Quell-Lemmas (z.B. App\Models\Verb) |
to_vocab_id | BIGINT UNSIGNED | Nein | ID des Ziel-Lemmas (worauf verwiesen wird) |
to_vocab_type | VARCHAR(255) | Nein | Vollständige Model-Klasse des Ziel-Lemmas |
form_from | VARCHAR(255) | Ja | Optionaler Pfad zu einer spezifischen Form im Quell-Lemma (z.B. 1_aktiv.3_perfekt.1_indikativ.1_sg1) |
form_to | VARCHAR(255) | Ja | Optionaler Pfad zu einer spezifischen Form im Ziel-Lemma |
relation | VARCHAR(50) | Ja | Art der Beziehung (siehe Verweis-Typen) |
confusion_factor | FLOAT | Ja | Verwechslungsgefahr zwischen 0 und 1 (für Übungen) |
created_at | TIMESTAMP | Ja | Erstellungszeitpunkt (Laravel-Standard) |
updated_at | TIMESTAMP | Ja | Letzte Aktualisierung (Laravel-Standard) |
deleted_at | TIMESTAMP | Ja | Soft-Delete-Zeitpunkt (Laravel Soft Deletes) |
Polymorphe Struktur
Die Kombination aus *_vocab_id und *_vocab_type ermöglicht polymorphe Beziehungen:
- Ein Verb kann auf ein Nomen verweisen
- Ein Adjektiv kann auf ein anderes Adjektiv verweisen
- Alle Wortarten können miteinander verknüpft werden
Indizes und Performance
Empfohlene Indizes für optimale Performance:
-- Index für ausgehende Verweise
CREATE INDEX idx_verweise_from ON verweise(from_vocab_id, from_vocab_type);
-- Index für eingehende Verweise
CREATE INDEX idx_verweise_to ON verweise(to_vocab_id, to_vocab_type);
-- Composite Index für Formverweise
CREATE INDEX idx_verweise_forms ON verweise(form_from, form_to);Verweis-Model
Das Model App\Models\Verweis repräsentiert einen einzelnen Verweis-Eintrag.
Model-Definition
<?php
namespace App\Models;
use App\Traits\Glossarium\Verifiable;
use App\Traits\hasReadableDates;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* @mixin Builder
*/
class Verweis extends Model
{
use SoftDeletes;
use Verifiable;
use hasReadableDates;
protected $table = 'verweise';
protected $appends = ['created_at_readable'];
protected $fillable = [
'id',
'from_vocab_id',
'from_vocab_type',
'to_vocab_id',
'to_vocab_type',
'form_from',
'form_to',
'relation',
'deleted_at',
'confusion_factor'
];
const RELATION_DESCRIPTION = [
'' => 'siehe auch',
null => 'siehe auch',
'etym' => 'ist etymologisch verwandt mit',
'part' => 'ist Bestandteil von',
'cont' => 'beinhaltet',
'lemm' => 'hat als eigentliches Lemma',
];
}Fillable Fields
Alle relevanten Felder sind fillable und können bei der Erstellung oder Aktualisierung eines Verweises verwendet werden:
Verweis::create([
'from_vocab_id' => 1,
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => 5,
'to_vocab_type' => 'App\Models\Verb',
'relation' => 'etym',
'confusion_factor' => 0.8,
]);Soft Deletes
Das Model verwendet Soft Deletes. Gelöschte Verweise werden nicht physisch entfernt, sondern nur mit einem Zeitstempel in deleted_at markiert:
// Verweis soft-löschen
$verweis->delete();
// Mit gelöschten Verweisen arbeiten
$alleVerweise = Verweis::withTrashed()->get();
// Nur gelöschte Verweise
$geloeschteVerweise = Verweis::onlyTrashed()->get();
// Wiederherstellen
$verweis->restore();
// Endgültig löschen
$verweis->forceDelete();RELATION_DESCRIPTION-Konstante
Die Konstante RELATION_DESCRIPTION bietet lesbare Beschreibungen für Relation-Codes:
$relation = $verweis->relation; // "etym"
$beschreibung = Verweis::RELATION_DESCRIPTION[$relation];
// => "ist etymologisch verwandt mit"Verwendete Traits
| Trait | Zweck |
|---|---|
SoftDeletes | Ermöglicht Soft-Delete-Funktionalität |
Verifiable | Validierung der Verweis-Daten (spezifisch für Glossarium) |
hasReadableDates | Stellt lesbare Datumsformate bereit (created_at_readable) |
Verweis-Typen (Relationen)
Die relation-Spalte definiert die Art der Beziehung zwischen zwei Lemmata. Der Wert ist optional (NULL/leer möglich).
Übersicht aller Relation-Codes
| Code | Beschreibung | Verwendung |
|---|---|---|
null / '' | "siehe auch" | Allgemeiner Verweis ohne spezifische Beziehung |
etym | "ist etymologisch verwandt mit" | Etymologische Beziehungen zwischen Wörtern |
part | "ist Bestandteil von" | Lemma ist Teil eines zusammengesetzten Wortes |
cont | "beinhaltet" | Lemma enthält ein anderes Lemma als Bestandteil |
lemm | "hat als eigentliches Lemma" | Verweis auf das Hauptlemma (bei Varianten) |
Detaillierte Beschreibung
1. Siehe auch (null / leer)
Verwendung: Allgemeine Querverweise ohne spezifische semantische Beziehung.
Beispiel:
// "amare" (lieben) → "odisse" (hassen) (Antonym)
Verweis::create([
'from_vocab_id' => $amare->id,
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => $odisse->id,
'to_vocab_type' => 'App\Models\Verb',
'relation' => null,
]);Use Case:
- Synonyme und Antonyme
- Thematisch verwandte Wörter
- Didaktische Querverweise
2. Etymologisch verwandt (etym)
Verwendung: Wörter mit gemeinsamer etymologischer Wurzel.
Beispiel:
// "venire" (kommen) ↔ "convenire" (zusammenkommen)
Verweis::create([
'from_vocab_id' => $venire->id,
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => $convenire->id,
'to_vocab_type' => 'App\Models\Verb',
'relation' => 'etym',
'confusion_factor' => 0.6,
]);Use Cases:
- Komposita mit Präfixen (advenire, evenire, pervenire...)
- Ableitungen (senator ← senex)
- Wortstämme erkennbar machen
3. Ist Bestandteil von (part)
Verwendung: Das Quell-Lemma ist Teil des Ziel-Lemmas.
Beispiel:
// "rex" ist Bestandteil von "regnum"
Verweis::create([
'from_vocab_id' => $rex->id,
'from_vocab_type' => 'App\Models\Nomen',
'to_vocab_id' => $regnum->id,
'to_vocab_type' => 'App\Models\Nomen',
'relation' => 'part',
]);Use Cases:
- Wortstämme und Ableitungen
- Komposita-Analyse
- Wortbildungslehre
4. Beinhaltet (cont)
Verwendung: Das Quell-Lemma enthält das Ziel-Lemma als Bestandteil (Umkehrung von part).
Beispiel:
// "respublica" beinhaltet "res" und "publicus"
Verweis::create([
'from_vocab_id' => $respublica->id,
'from_vocab_type' => 'App\Models\Nomen',
'to_vocab_id' => $res->id,
'to_vocab_type' => 'App\Models\Nomen',
'relation' => 'cont',
]);
Verweis::create([
'from_vocab_id' => $respublica->id,
'from_vocab_type' => 'App\Models\Nomen',
'to_vocab_id' => $publicus->id,
'to_vocab_type' => 'App\Models\Adjektiv',
'relation' => 'cont',
]);Use Cases:
- Zusammengesetzte Wörter zerlegen
- Morphologie verstehen
- Vokabellernen durch Wortbestandteile
5. Hat als eigentliches Lemma (lemm)
Verwendung: Das Quell-Lemma ist eine Variante oder Nebenform, das Ziel-Lemma ist die Hauptform.
Beispiel:
// Archaische Form "honos" → Hauptform "honor"
Verweis::create([
'from_vocab_id' => $honos->id,
'from_vocab_type' => 'App\Models\Nomen',
'to_vocab_id' => $honor->id,
'to_vocab_type' => 'App\Models\Nomen',
'relation' => 'lemm',
]);Use Cases:
- Archaische Formen
- Dialektvarianten
- Orthographische Varianten (z.B. caussa → causa)
Formverweise
Was sind Formverweise?
Formverweise beziehen sich nicht auf das gesamte Lemma, sondern auf spezifische flektierte Formen. Sie werden verwendet, wenn nur einzelne Formen eines Wortes auf Formen eines anderen Wortes verweisen.
Pfad-Notation für Formen
Die Felder form_from und form_to verwenden die Pfad-Notation aus dem Morphologie-JSON:
Syntax: Punkt-separierte Schlüssel, die den Pfad durch das hierarchische JSON beschreiben.
Beispiel-Pfade:
1_aktiv.3_perfekt.1_indikativ.1_sg1
→ Aktiv, Perfekt, Indikativ, 1. Person Singular
→ Form: "amavi"
1_sg.1_nom
→ Singular, Nominativ
→ Form: "amicus"
1_pos.1_sg.1_mask.1_nom
→ Positiv, Singular, Maskulinum, Nominativ
→ Form: "bonus"Hierarchie-Schlüssel (Referenz)
Die Pfadnotation verwendet die standardisierten Schlüssel aus dem Morphologie-System:
Verben
1_aktiv / 2_passiv / 3_gerundium / 4_gerundiv / 5_supin
└─ 1_praesens / 2_imperfekt / 3_perfekt / 4_plusquamperfekt / 5_futur / 6_futur2
└─ 0_infinitiv / 1_indikativ / 2_konjunktiv / 3_imperativ / 4_partizip
└─ 1_sg1 / 2_sg2 / 3_sg3 / 4_pl1 / 5_pl2 / 6_pl3Nomina/Adjektive
1_sg / 2_pl
└─ 1_nom / 2_gen / 3_dat / 4_akk / 5_vok / 6_abl
└─ (bei Adjektiven) 1_mask / 2_fem / 3_neutrPraktisches Beispiel: incipere → coepere
Das Verb incipere (beginnen) hat im Perfektstamm eine gebräuchliche Alternativform coepi (neben der regulären Form incepi).
Szenario
- Lemma: incipere (ID: 10)
- Alternativform-Lemma: coepere (ID: 15)
- Betroffene Form: 1. Person Singular Perfekt Aktiv Indikativ
- Pfad:
1_aktiv.3_perfekt.1_indikativ.1_sg1
Implementierung als Formverweis
Verweis::create([
'from_vocab_id' => 10, // incipere
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => 15, // coepere
'to_vocab_type' => 'App\Models\Verb',
'form_from' => '1_aktiv.3_perfekt.1_indikativ.1_sg1',
'form_to' => '1_aktiv.3_perfekt.1_indikativ.1_sg1',
'relation' => null,
'confusion_factor' => 0.3,
]);Ergebnis
Bei Abfrage der Form 1_aktiv.3_perfekt.1_indikativ.1_sg1 von incipere:
- System findet Verweis
- Lädt die entsprechende Form von coepere: "coepi"
- Zeigt beide Formen an: "incepi / coepi" (je nach Frontend-Logik)
Weitere Formverweis-Beispiele
Beispiel: Suppletivformen
esse (sein) hat im Futur suppletive Formen von fore:
// Futur-Infinitiv: "esse" → "fore"
Verweis::create([
'from_vocab_id' => $esse->id,
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => $fore->id,
'to_vocab_type' => 'App\Models\Verb',
'form_from' => '1_aktiv.5_futur.0_infinitiv',
'form_to' => '1_aktiv.1_praesens.0_infinitiv', // "fore" ist eigentlich ein Präsens-Infinitiv
'relation' => 'lemm',
]);Beispiel: Genus-Wechsel bei Nomina
Einige Nomina haben verschiedene Genera mit unterschiedlichen Bedeutungen:
// "finis, is m." (Grenze) ↔ "finis, is f." (Ende)
// Hier würde man zwei separate Lemmata anlegen und per Verweis verbinden
Verweis::create([
'from_vocab_id' => $finis_m->id,
'from_vocab_type' => 'App\Models\Nomen',
'to_vocab_id' => $finis_f->id,
'to_vocab_type' => 'App\Models\Nomen',
'relation' => null,
'confusion_factor' => 0.9, // Hohe Verwechslungsgefahr!
]);Alternativformen: Zwei Ansätze
Wenn ein Wort mehrere gültige Formen hat, gibt es zwei Möglichkeiten der Abbildung.
Ansatz 1: Inline im JSON
Prinzip: Alternativformen werden direkt im morph-JSON als Slash-getrennte Werte gespeichert.
Beispiel
{
"1_aktiv": {
"3_perfekt": {
"1_indikativ": {
"1_sg1": "coepi / incepi",
"2_sg2": "coepisti / incepisti",
"3_sg3": "coepit / incepit"
}
}
}
}Implementierung
Beim Morphing wird die Alternativform direkt eingetragen:
// In VerbMorpher oder manuell
$morph['1_aktiv']['3_perfekt']['1_indikativ']['1_sg1'] = 'coepi / incepi';Vorteile
- Einfach: Keine zusätzlichen Datenbankeinträge
- Schnell: Kein JOIN nötig, direkt im JSON
- Kompakt: Eine Abfrage liefert alle Formen
- Frontend-freundlich: Einfaches Splitting bei Anzeige
Nachteile
- Nicht strukturiert abfragbar: Schwierig, alle Wörter mit Alternativformen zu finden
- Keine Metadaten: Keine Information über die Art der Beziehung oder Verwechslungsgefahr
- Nicht für Übungen nutzbar: Schwieriger Zugriff für Übungsgenerierung
- Polymorphie unmöglich: Keine Verweise auf andere Wortarten
Verwendung
Ideal für:
- Reine Formvarianten ohne semantische Bedeutung
- Orthographische Varianten (z.B. sylva / silva)
- Häufig vorkommende Alternativformen
Ansatz 2: Verweis-Eintrag
Prinzip: Jede Alternativform wird als separater Eintrag in der verweise-Tabelle gespeichert.
Beispiel
Verweis::create([
'from_vocab_id' => 10, // incipere
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => 15, // coepere
'to_vocab_type' => 'App\Models\Verb',
'form_from' => '1_aktiv.3_perfekt.1_indikativ.1_sg1',
'form_to' => '1_aktiv.3_perfekt.1_indikativ.1_sg1',
'relation' => null,
'confusion_factor' => 0.3,
]);Implementierung
Die Verweis-Einträge werden explizit erstellt und können über die Accessor-Methoden abgerufen werden:
$verb = Verb::find(10);
$formverweise = $verb->verweise_from_formen_to_vocabformen();Vorteile
- Strukturiert: Abfragbar, filterfähig, indizierbar
- Metadaten: Relation, Verwechslungsgefahr, Zeitstempel
- Flexibel: Polymorphe Beziehungen möglich
- Übungsintegration: Direkt für Übungen nutzbar (z.B. "Welche Formen werden häufig verwechselt?")
- Bidirektional: Eingehende und ausgehende Verweise können getrennt abgerufen werden
Nachteile
- Aufwändiger: Zusätzliche Datenbankeinträge erforderlich
- Performance: JOIN nötig beim Abrufen
- Komplexität: Frontend muss Verweise und JSON-Formen kombinieren
Verwendung
Ideal für:
- Semantisch relevante Alternativformen
- Suppletivformen (wie esse → fore)
- Alternativformen mit hoher Verwechslungsgefahr
- Polymorphe Verweise (Verb → Nomen)
- Übungsgenerierung
Entscheidungsmatrix: Wann welcher Ansatz?
| Kriterium | Inline JSON | Verweis-Eintrag |
|---|---|---|
| Nur Formvarianten | ✓ | - |
| Semantische Beziehung | - | ✓ |
| Verwechslungsgefahr relevant | - | ✓ |
| Übungsintegration | - | ✓ |
| Polymorphe Beziehung | - | ✓ |
| Performance wichtig | ✓ | - |
| Häufige Abfrage | ✓ | - |
| Metadaten benötigt | - | ✓ |
| Einfache Orthographie-Varianten | ✓ | - |
Hybridansatz (empfohlen)
In der Praxis wird oft ein Hybridansatz verwendet:
- Inline: Einfache, häufige Formvarianten ohne semantische Bedeutung
- Verweis-Eintrag: Komplexe, semantisch relevante Alternativformen oder solche mit Verwechslungsgefahr
Beispiel:
// Inline: Einfache Variante
$morph['1_sg']['1_nom'] = 'sylva / silva';
// Verweis: Semantisch relevant
Verweis::create([
'from_vocab_id' => $ferre->id,
'to_vocab_id' => $tollere->id,
'form_from' => '1_aktiv.3_perfekt.1_indikativ.1_sg1',
'form_to' => '1_aktiv.3_perfekt.1_indikativ.1_sg1',
'relation' => 'lemm',
'confusion_factor' => 0.8,
]);
// "ferre" hat suppletive Perfektformen von "tollere" (tuli, tulisti...)Accessor-Methoden in Vocab
Die abstrakte Basisklasse Vocab definiert drei zentrale Accessor-Methoden für den Zugriff auf Verweise. Diese werden als dynamische Attribute bereitgestellt.
1. getVerweiseFromAttribute()
Zweck: Liefert alle ausgehenden Verweise eines Lemmas (ohne Formverweise).
Definition
/**
* Returns Collection of Words that a pointer refers to
* @return Collection
*/
public function getVerweiseFromAttribute(): Collection
{
return (DB::table('verweise')->where([
['from_vocab_id', '=', $this->id],
['from_vocab_type', '=', get_class($this)]])->get())->map(function ($result) {
if ($result->to_vocab_type && strlen($result->to_vocab_type) > 0) {
$result->to_vocab = self::$ClassModelLookUpTable[ $result->to_vocab_type ]::find($result->to_vocab_id);
}
return $result;
});
}Funktionsweise
- Abfrage der
verweise-Tabelle nachfrom_vocab_idundfrom_vocab_type - Für jeden Verweis wird das Ziel-Lemma geladen und als
to_vocabhinzugefügt - Rückgabe als Laravel Collection
Verwendung
$verb = Verb::find(1);
$ausgehendeVerweise = $verb->verweise_from;
foreach ($ausgehendeVerweise as $verweis) {
echo "Verweis auf: " . $verweis->to_vocab->lemma;
echo " (Relation: " . Verweis::RELATION_DESCRIPTION[$verweis->relation] . ")";
}Beispiel-Output
// Verb "venire" (ID: 1)
$venire->verweise_from;
// Collection mit:
// [
// {
// id: 5,
// from_vocab_id: 1,
// from_vocab_type: "App\Models\Verb",
// to_vocab_id: 8,
// to_vocab_type: "App\Models\Verb",
// relation: "etym",
// to_vocab: Verb { id: 8, lemma: "convenire", ... }
// },
// ...
// ]2. getVerweiseToAttribute()
Zweck: Liefert alle eingehenden Verweise auf ein Lemma (ohne Formverweise).
Definition
/**
* Returns Collection of Words that a pointer refers from
* @return Collection
*/
public function getVerweiseToAttribute(): Collection
{
return (DB::table('verweise')->where([
['to_vocab_id', '=', $this->id],
['to_vocab_type', '=', get_class($this)]])->get())->map(function ($result) {
if ($result->from_vocab_type && strlen($result->from_vocab_type) > 0) {
$result->from_vocab = self::$ClassModelLookUpTable[ $result->from_vocab_type ]::find($result->from_vocab_id);
}
return $result;
});
}Funktionsweise
- Abfrage der
verweise-Tabelle nachto_vocab_idundto_vocab_type - Für jeden Verweis wird das Quell-Lemma geladen und als
from_vocabhinzugefügt - Rückgabe als Laravel Collection
Verwendung
$verb = Verb::find(8); // convenire
$eingehendeVerweise = $verb->verweise_to;
foreach ($eingehendeVerweise as $verweis) {
echo "Verweis von: " . $verweis->from_vocab->lemma;
echo " (Relation: " . Verweis::RELATION_DESCRIPTION[$verweis->relation] . ")";
}Use Case
Eingehende Verweise sind nützlich, um zu zeigen:
- "Welche Wörter sind mit diesem Lemma verwandt?"
- "Welche Komposita enthalten dieses Wort als Bestandteil?"
3. getVerweiseToFormenAttribute()
Zweck: Liefert Formverweise, die auf Formen dieses Lemmas zeigen.
Definition
/**
* Returns Collection of Words that a pointer refers from
* @return Collection
*/
public function getVerweiseToFormenAttribute(): Collection
{
return (DB::table('verweise')->where([
['to_vocab_id', '=', $this->id],
['to_vocab_type', '=', get_class($this)]])->get())->map(function ($result) {
return [$result->form_to => $result->form_from];
});
}Funktionsweise
- Abfrage aller Verweise, die auf dieses Lemma zeigen
- Rückgabe als Key-Value-Paare:
[form_to => form_from] - Mapping für Frontend-Verwendung optimiert
Verwendung
$verb = Verb::find(15); // coepere
$formverweise = $verb->verweise_to_formen;
// Collection:
// [
// ["1_aktiv.3_perfekt.1_indikativ.1_sg1" => "1_aktiv.3_perfekt.1_indikativ.1_sg1"],
// ...
// ]Hinweis
Diese Methode liefert nur das Mapping der Pfade, nicht die vollständigen Lemma-Objekte. Für vollständige Informationen siehe hasVerweise-Trait.
Appending der Verweise
Die Accessor-Methoden sind in der Konstante APPENDEDFIELDS_VERWEISE definiert:
const APPENDEDFIELDS_VERWEISE = ['verweise_to', 'verweise_to_formen', 'verweise_from'];Um Verweise in einem Query automatisch zu laden:
$verb = Verb::find(1);
$verb->append(Vocab::APPENDEDFIELDS_VERWEISE);
// Jetzt verfügbar:
$verb->verweise_from;
$verb->verweise_to;
$verb->verweise_to_formen;hasVerweise-Trait
Das Trait App\Traits\Glossarium\hasVerweise erweitert die Verweis-Funktionalität mit zusätzlichen, filterfähigen Methoden.
Trait-Definition
<?php
namespace App\Traits\Glossarium;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
/**
* Ein Trait für alle Vokabeln bzw. die verschiedenen Wortarten
*/
trait hasVerweise
{
// Methoden siehe unten
}Methoden im Detail
1. verweise_from()
Zweck: Liefert ausgehende Verweise ohne Formverweise (Filter: form_from und form_to müssen NULL/leer sein).
/**
* Gibt alle Verweise zurück, die VON diesem Wort auf andere Wörter zeigen
* @return Collection
*/
public function verweise_from(): Collection
{
return (DB::table('verweise')->where(function ($query) {
$query->where('form_from', '=', null)
->orWhere('form_from', '=', '');
})
->where(function ($query) {
$query->where('form_to', '=', null)
->orWhere('form_to', '=', '');
})
->where('from_vocab_id', '=', $this->id)
->where('from_vocab_type', '=', get_class($this))
->get())->map(function ($result) {
if ($result->to_vocab_type && strlen($result->to_vocab_type) > 0) {
$result->to_vocab = self::$ClassModelLookUpTable[ $result->to_vocab_type ]::find($result->to_vocab_id);
}
return $result;
});
}Unterschied zu getVerweiseFromAttribute():
- Filtert explizit Formverweise heraus
- Nur "Lemma-zu-Lemma"-Verweise
Verwendung:
$verb = Verb::find(1);
$lemmaVerweise = $verb->verweise_from();
// Nur allgemeine Verweise, keine formspezifischen2. verweise_to()
Zweck: Liefert eingehende Verweise ohne Formverweise.
/**
* Gibt alle Verweise zurück, die AUF dieses Wort zeigen
* @return Collection
*/
public function verweise_to(): Collection
{
return (DB::table('verweise')->where(function ($query) {
$query->where('form_from', '=', null)
->orWhere('form_from', '=', '');
})
->where(function ($query) {
$query->where('form_to', '=', null)
->orWhere('form_to', '=', '');
})
->where('to_vocab_id', '=', $this->id)
->where('to_vocab_type', '=', get_class($this))
->get())->map(function ($result) {
if ($result->from_vocab_type && strlen($result->from_vocab_type) > 0) {
$result->from_vocab = self::$ClassModelLookUpTable[ $result->from_vocab_type ]::find($result->from_vocab_id);
}
return $result;
});
}Verwendung:
$verb = Verb::find(8);
$eingehend = $verb->verweise_to();3. verweise_from_formen_to_vocabformen()
Zweck: Liefert nur Formverweise, bei denen form_from und form_to gesetzt sind.
/**
* Gibt alle Verweise zurück, bei denen irgendeine (Sonder-)form auf eine Form dieses Wortes zeigt.
* Beispiel: Die Form "superasses" verweist auf die Form "superavisses"
* und dabei ist das Verb-Model und die Verb-ID von "superare" angegeben
* @return Collection
*/
public function verweise_from_formen_to_vocabformen(): Collection
{
return (DB::table('verweise')->whereNotNull('form_from')->whereNotNull('form_to')->where([
['to_vocab_id', '=', $this->id],
['to_vocab_type', '=', get_class($this)]])->get());
}Verwendung:
$verb = Verb::find(10); // incipere
$formverweise = $verb->verweise_from_formen_to_vocabformen();
// Collection mit Formverweisen:
// [
// {
// from_vocab_id: 15,
// form_from: "1_aktiv.3_perfekt.1_indikativ.1_sg1",
// to_vocab_id: 10,
// form_to: "1_aktiv.3_perfekt.1_indikativ.1_sg1",
// ...
// }
// ]4. verweise_all()
Zweck: Liefert alle Verweise (ausgehend, eingehend, Formverweise), optional gruppiert.
/**
* Gibt alle Verweise zurück, die VON oder AUF dieses Wort zeigen
* @param bool $grouped
* @return Collection
*/
public function verweise_all($grouped = false): Collection
{
if ($grouped) {
return collect([
'verweise_from' => $this->verweise_from(),
'verweise_to' => $this->verweise_to(),
'verweise_from_formen_to_vocabformen' => $this->verweise_from_formen_to_vocabformen(),
]);
} else {
return $this->verweise_from()->merge($this->verweise_to())->merge($this->verweise_from_formen_to_vocabformen());
}
}Verwendung:
// Alle Verweise als flache Collection
$alleVerweise = $verb->verweise_all();
// Gruppiert nach Typ
$gruppiertVerweise = $verb->verweise_all(true);
// Zugriff auf gruppierte Verweise:
$gruppiertVerweise['verweise_from']; // Ausgehende Lemma-Verweise
$gruppiertVerweise['verweise_to']; // Eingehende Lemma-Verweise
$gruppiertVerweise['verweise_from_formen_to_vocabformen']; // FormverweiseUse Case:
- Vollständige Verweis-Übersicht in der Lemma-Detailansicht
- Export von Verweisen
- Analyse von Beziehungen
Integration des Traits
Das Trait wird in allen Wortart-Models verwendet, die von Vocab erben:
class Verb extends Vocab
{
use hasVerweise;
// ...
}Dadurch stehen alle Methoden automatisch zur Verfügung:
$verb = Verb::find(1);
$verb->verweise_from();
$verb->verweise_to();
$verb->verweise_all(true);Polymorphe Beziehungen
Das Verweissystem nutzt polymorphe Beziehungen, um Flexibilität bei der Verknüpfung verschiedener Wortarten zu ermöglichen.
Prinzip
Anstelle einer festen foreign_key-Beziehung verwendet das System zwei Felder:
*_vocab_id: Die ID des Lemmas*_vocab_type: Die vollständige Model-Klasse (z.B.App\Models\Verb)
Vorteile
- Wortartübergreifend: Ein Verb kann auf ein Nomen verweisen
- Flexibel: Neue Wortarten können ohne Schema-Änderungen integriert werden
- Konsistent: Einheitliche Struktur für alle Verweis-Typen
Beispiel: Verb → Nomen
// "regnare" (herrschen) → "regnum" (Königreich)
Verweis::create([
'from_vocab_id' => $regnare->id,
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => $regnum->id,
'to_vocab_type' => 'App\Models\Nomen',
'relation' => 'etym',
]);Beispiel: Adjektiv → Nomen
// "regius" (königlich) → "rex" (König)
Verweis::create([
'from_vocab_id' => $regius->id,
'from_vocab_type' => 'App\Models\Adjektiv',
'to_vocab_id' => $rex->id,
'to_vocab_type' => 'App\Models\Nomen',
'relation' => 'part',
]);Model-Auflösung
Die Accessor-Methoden lösen die Model-Klassen automatisch über die $ClassModelLookUpTable auf:
// In getVerweiseFromAttribute():
if ($result->to_vocab_type && strlen($result->to_vocab_type) > 0) {
$result->to_vocab = self::$ClassModelLookUpTable[ $result->to_vocab_type ]::find($result->to_vocab_id);
}Lookup-Tabelle (aus Vocab.php):
static array $ClassModelLookUpTable = [
'App\Models\Adjektiv' => Adjektiv::class,
'App\Models\Eigenname' => Eigenname::class,
'App\Models\Nomen' => Nomen::class,
'App\Models\Numerale' => Numerale::class,
'App\Models\Partikel' => Partikel::class,
'App\Models\Pronomen' => Pronomen::class,
'App\Models\Verb' => Verb::class,
'App\Models\Wendung' => Wendung::class,
];Abfragen über Wortarten hinweg
// Alle Verweise, die von Verben auf Nomina zeigen
$verbNomenVerweise = DB::table('verweise')
->where('from_vocab_type', 'App\Models\Verb')
->where('to_vocab_type', 'App\Models\Nomen')
->get();
// Alle etymologischen Verweise zwischen beliebigen Wortarten
$etymVerweise = DB::table('verweise')
->where('relation', 'etym')
->get();Verwendungsbeispiele
Beispiel 1: Einfachen Verweis erstellen
use App\Models\Verweis;
use App\Models\Verb;
$amare = Verb::where('lemma', 'amare')->first();
$odisse = Verb::where('lemma', 'odisse')->first();
// Antonym-Verweis erstellen
$verweis = Verweis::create([
'from_vocab_id' => $amare->id,
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => $odisse->id,
'to_vocab_type' => 'App\Models\Verb',
'relation' => null, // "siehe auch"
'confusion_factor' => 0.2,
]);Beispiel 2: Etymologischen Verweis mit hoher Verwechslungsgefahr erstellen
use App\Models\Verweis;
use App\Models\Verb;
$venire = Verb::where('lemma', 'venire')->first();
$convenire = Verb::where('lemma', 'convenire')->first();
Verweis::create([
'from_vocab_id' => $venire->id,
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => $convenire->id,
'to_vocab_type' => 'App\Models\Verb',
'relation' => 'etym',
'confusion_factor' => 0.75,
]);
// Bidirektionaler Verweis (optional)
Verweis::create([
'from_vocab_id' => $convenire->id,
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => $venire->id,
'to_vocab_type' => 'App\Models\Verb',
'relation' => 'etym',
'confusion_factor' => 0.75,
]);Beispiel 3: Formverweis erstellen (Suppletivformen)
use App\Models\Verweis;
use App\Models\Verb;
$incipere = Verb::where('lemma', 'incipere')->first();
$coepere = Verb::where('lemma', 'coepere')->first();
// Perfekt-Stammformen verweisen
Verweis::create([
'from_vocab_id' => $incipere->id,
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => $coepere->id,
'to_vocab_type' => 'App\Models\Verb',
'form_from' => '1_aktiv.3_perfekt.1_indikativ.1_sg1',
'form_to' => '1_aktiv.3_perfekt.1_indikativ.1_sg1',
'relation' => null,
]);
// Weitere Perfektformen
Verweis::create([
'from_vocab_id' => $incipere->id,
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => $coepere->id,
'to_vocab_type' => 'App\Models\Verb',
'form_from' => '1_aktiv.3_perfekt.1_indikativ.2_sg2',
'form_to' => '1_aktiv.3_perfekt.1_indikativ.2_sg2',
'relation' => null,
]);Beispiel 4: Verweise eines Lemmas abrufen
use App\Models\Verb;
$verb = Verb::find(1);
// Alle ausgehenden Verweise (ohne Formverweise)
$ausgehend = $verb->verweise_from;
foreach ($ausgehend as $verweis) {
echo "Verweist auf: " . $verweis->to_vocab->lemma . "\n";
echo "Relation: " . Verweis::RELATION_DESCRIPTION[$verweis->relation] . "\n";
echo "Verwechslungsgefahr: " . ($verweis->confusion_factor * 100) . "%\n\n";
}
// Alle eingehenden Verweise
$eingehend = $verb->verweise_to;
foreach ($eingehend as $verweis) {
echo "Verweis von: " . $verweis->from_vocab->lemma . "\n";
}
// Formverweise
$formverweise = $verb->verweise_from_formen_to_vocabformen();
foreach ($formverweise as $verweis) {
echo "Form-Verweis: " . $verweis->form_from . " → " . $verweis->form_to . "\n";
}Beispiel 5: Alle Verweise mit Metadaten abrufen (gruppiert)
use App\Models\Verb;
$verb = Verb::find(1);
$alleVerweise = $verb->verweise_all($grouped = true);
// Ausgehende Lemma-Verweise
echo "Ausgehende Verweise:\n";
foreach ($alleVerweise['verweise_from'] as $verweis) {
echo "- {$verweis->to_vocab->lemma} ({$verweis->relation})\n";
}
// Eingehende Lemma-Verweise
echo "\nEingehende Verweise:\n";
foreach ($alleVerweise['verweise_to'] as $verweis) {
echo "- {$verweis->from_vocab->lemma} ({$verweis->relation})\n";
}
// Formverweise
echo "\nFormverweise:\n";
foreach ($alleVerweise['verweise_from_formen_to_vocabformen'] as $verweis) {
echo "- {$verweis->form_from} → {$verweis->form_to}\n";
}Beispiel 6: Polymorphe Verweise abfragen (Verb → Nomen)
use App\Models\Verweis;
use App\Models\Verb;
use App\Models\Nomen;
$regnare = Verb::where('lemma', 'regnare')->first();
$rex = Nomen::where('lemma', 'rex')->first();
// Verweis erstellen
Verweis::create([
'from_vocab_id' => $regnare->id,
'from_vocab_type' => 'App\Models\Verb',
'to_vocab_id' => $rex->id,
'to_vocab_type' => 'App\Models\Nomen',
'relation' => 'part', // "regnare" ist Teil von "rex" (etymologisch)
]);
// Verweise abrufen
$verweise = $regnare->verweise_from;
foreach ($verweise as $verweis) {
echo "Typ: " . class_basename($verweis->to_vocab_type) . "\n";
echo "Lemma: " . $verweis->to_vocab->lemma . "\n";
}Beispiel 7: Verweise für Übungen nutzen
use App\Models\Verweis;
// Alle Wortpaare mit hoher Verwechslungsgefahr (> 0.7)
$verwechslungsVerweise = Verweis::where('confusion_factor', '>', 0.7)->get();
foreach ($verwechslungsVerweise as $verweis) {
$fromVocab = Vocab::$ClassModelLookUpTable[$verweis->from_vocab_type]::find($verweis->from_vocab_id);
$toVocab = Vocab::$ClassModelLookUpTable[$verweis->to_vocab_type]::find($verweis->to_vocab_id);
echo "Übung: Unterscheide {$fromVocab->lemma} und {$toVocab->lemma}\n";
}Beispiel 8: Bidirektionale Verweise erstellen (Helfer-Funktion)
use App\Models\Verweis;
/**
* Erstellt bidirektionale Verweise zwischen zwei Lemmata
*/
function createBidirectionalVerweis($vocab1, $vocab2, $relation = null, $confusionFactor = 0.5)
{
// Hin-Verweis
Verweis::create([
'from_vocab_id' => $vocab1->id,
'from_vocab_type' => get_class($vocab1),
'to_vocab_id' => $vocab2->id,
'to_vocab_type' => get_class($vocab2),
'relation' => $relation,
'confusion_factor' => $confusionFactor,
]);
// Rück-Verweis
Verweis::create([
'from_vocab_id' => $vocab2->id,
'from_vocab_type' => get_class($vocab2),
'to_vocab_id' => $vocab1->id,
'to_vocab_type' => get_class($vocab1),
'relation' => $relation,
'confusion_factor' => $confusionFactor,
]);
}
// Verwendung
$amare = Verb::where('lemma', 'amare')->first();
$odisse = Verb::where('lemma', 'odisse')->first();
createBidirectionalVerweis($amare, $odisse, null, 0.3);Verwechslungsgefahr (confusion_factor)
Was ist der confusion_factor?
Der confusion_factor ist ein Fließkommawert zwischen 0 und 1, der angibt, wie hoch die Wahrscheinlichkeit ist, dass zwei Lemmata (oder Formen) miteinander verwechselt werden.
Wertebereich und Bedeutung
| Wert | Bedeutung | Verwendung |
|---|---|---|
0.0 - 0.2 | Sehr geringe Verwechslungsgefahr | Entfernte semantische Beziehungen |
0.2 - 0.4 | Geringe Verwechslungsgefahr | Thematisch verwandt, aber klar unterscheidbar |
0.4 - 0.6 | Mittlere Verwechslungsgefahr | Ähnliche Bedeutung oder Form |
0.6 - 0.8 | Hohe Verwechslungsgefahr | Häufig verwechselte Wörter |
0.8 - 1.0 | Sehr hohe Verwechslungsgefahr | Fast identische Form oder Bedeutung |
Verwendung in Übungen
Der confusion_factor wird primär in Übungen genutzt:
Use Case 1: Übung "Bedeutungen zuordnen"
// Übung generieren mit häufig verwechselten Wörtern
$highConfusionPairs = Verweis::where('confusion_factor', '>', 0.7)
->inRandomOrder()
->limit(10)
->get();
foreach ($highConfusionPairs as $verweis) {
// Erstelle Multiple-Choice-Frage
// "Was bedeutet '{$verweis->from_vocab->lemma}'?"
// Falsche Antwort: $verweis->to_vocab->bedeutung
}Use Case 2: Übung "Formen unterscheiden"
// Formverweise mit hoher Verwechslungsgefahr
$confusingForms = Verweis::whereNotNull('form_from')
->where('confusion_factor', '>', 0.6)
->get();Use Case 3: Adaptive Lernsysteme
// Häufiger abfragen, wenn Verwechslungsgefahr hoch
$learningWeight = $verweis->confusion_factor * 2;
// Höherer Wert = häufigeres Wiederholen in LerneinheitenBeispiele für confusion_factor-Werte
Beispiel 1: finis, is m./f.
// "finis" (m.) = Grenze vs. "finis" (f.) = Ende
// SEHR hohe Verwechslungsgefahr (identisches Lemma, verschiedene Bedeutungen)
'confusion_factor' => 0.95Beispiel 2: venire vs. convenire
// Ähnliche Form, verwandte aber unterschiedliche Bedeutung
'confusion_factor' => 0.65Beispiel 3: amare vs. odisse
// Antonyme, semantisch verwandt, aber klar unterscheidbar
'confusion_factor' => 0.2Beispiel 4: coepi vs. incepi
// Alternativformen, mittlere Verwechslungsgefahr
'confusion_factor' => 0.4Berechnung des confusion_factor
Es gibt keine automatische Berechnung. Der Wert wird manuell oder heuristisch festgelegt basierend auf:
- Morphologische Ähnlichkeit: Wie ähnlich sind die Formen?
- Semantische Nähe: Wie verwandt sind die Bedeutungen?
- Didaktische Erfahrung: Werden die Wörter tatsächlich häufig verwechselt?
- Corpus-Analyse: Wie oft werden die Wörter in ähnlichen Kontexten verwendet?
Null-Werte
Wenn confusion_factor NULL ist, bedeutet das:
- Keine spezifische Verwechslungsgefahr definiert
- Verweis ist rein informativ (z.B. etymologische Beziehung)
Verwendung in der Applikation
Integration in Übungen
Das Verweissystem ist eng mit dem Übungssystem verzahnt.
1. Übung "Bedeutungen zuordnen"
// In UebungBedeutungenZuordnenController oder API
// Hole Verweise mit hoher Verwechslungsgefahr
$confusingPairs = Verweis::where('confusion_factor', '>', 0.6)
->with(['fromVocab', 'toVocab']) // Eager Loading
->get();
// Erstelle Distraktoren (falsche Antworten)
foreach ($confusingPairs as $pair) {
$question = [
'lemma' => $pair->from_vocab->lemma,
'correct_answer' => $pair->from_vocab->bedeutung,
'distractors' => [$pair->to_vocab->bedeutung, /* weitere */],
];
}2. Übung "Formen erkennen"
// Hole Formverweise für spezifische Formen
$formVerweise = Verweis::whereNotNull('form_from')
->whereNotNull('form_to')
->get();
foreach ($formVerweise as $verweis) {
// Zeige beide Formen und lasse Schüler die richtige identifizieren
}Anzeige im Frontend
Lemma-Detailansicht
<template>
<div class="verweise-section">
<h3>Verwandte Wörter</h3>
<ul>
<li v-for="verweis in verweiseFrom" :key="verweis.id">
<router-link :to="`/glossarium/${verweis.to_vocab.route_name}/${verweis.to_vocab.id}`">
<span class="font-bold font-serif">{{ verweis.to_vocab.lemma }}</span>
</router-link>
<span class="text-sm text-grey-600">
({{ getRelationDescription(verweis.relation) }})
</span>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
verweiseFrom: [],
};
},
mounted() {
this.loadVerweise();
},
methods: {
async loadVerweise() {
const response = await haxiosAPIClient.get(`/vocab/${this.vocabId}/verweise`);
this.verweiseFrom = response.data.verweise_from;
},
getRelationDescription(relation) {
const descriptions = {
'': 'siehe auch',
'etym': 'etymologisch verwandt',
'part': 'ist Bestandteil von',
'cont': 'beinhaltet',
'lemm': 'Hauptlemma',
};
return descriptions[relation] || 'siehe auch';
},
},
};
</script>Formverweise im Morphologie-Viewer
<template>
<div class="morphologie-form">
<span class="form-value">{{ form }}</span>
<span v-if="hasFormVerweis(formPath)" class="form-verweis">
/ {{ getFormVerweis(formPath) }}
</span>
</div>
</template>
<script>
export default {
props: ['vocab', 'formPath', 'form'],
methods: {
hasFormVerweis(path) {
return this.vocab.verweise_to_formen.some(v => v.form_to === path);
},
getFormVerweis(path) {
const verweis = this.vocab.verweise_to_formen.find(v => v.form_to === path);
if (verweis) {
// Hole die tatsächliche Form vom Ziel-Lemma
return this.resolveForm(verweis.from_vocab_id, verweis.form_from);
}
return null;
},
},
};
</script>Performance-Überlegungen
Problem: N+1 Queries
Beim Laden von Verweisen über Accessor-Methoden:
$verbs = Verb::all();
foreach ($verbs as $verb) {
$verweise = $verb->verweise_from; // N+1 Problem!
}Lösung 1: Eager Loading vermeiden
// Lade Verweise nur bei Bedarf
$verb = Verb::find(1);
$verb->append('verweise_from');Lösung 2: Explizite Abfrage mit JOIN
$verbsWithVerweise = DB::table('verben')
->leftJoin('verweise', function($join) {
$join->on('verben.id', '=', 'verweise.from_vocab_id')
->where('verweise.from_vocab_type', '=', 'App\Models\Verb');
})
->select('verben.*', 'verweise.*')
->get();Lösung 3: Caching
use Illuminate\Support\Facades\Cache;
$verweise = Cache::remember("vocab_{$vocab->id}_verweise", 3600, function() use ($vocab) {
return $vocab->verweise_all(true);
});Caching
Verweise ändern sich selten und eignen sich gut für Caching:
// In einem Service oder Repository
public function getVerweiseWithCache($vocabId, $vocabType)
{
$cacheKey = "verweise_{$vocabType}_{$vocabId}";
return Cache::tags(['verweise', $vocabType])->remember($cacheKey, 3600, function() use ($vocabId, $vocabType) {
$vocab = $vocabType::find($vocabId);
return $vocab->verweise_all(true);
});
}
// Cache invalidieren bei Änderungen
public function clearVerweiseCache($vocabId, $vocabType)
{
Cache::tags(['verweise', $vocabType])->forget("verweise_{$vocabType}_{$vocabId}");
}Best Practices
1. Wann Inline-Alternativen, wann Verweise?
Inline verwenden für:
- Einfache orthographische Varianten (sylva / silva)
- Häufig vorkommende Formvarianten ohne semantische Bedeutung
- Wenn keine Metadaten (Relation, Verwechslungsgefahr) benötigt werden
- Performance-kritische Anwendungen (direkt im JSON, kein JOIN)
Verweise verwenden für:
- Semantisch relevante Beziehungen
- Suppletivformen (esse → fore)
- Wenn
confusion_factorrelevant ist (Übungen) - Polymorphe Beziehungen (wortartübergreifend)
- Wenn bidirektionale Navigation erwünscht ist
2. Konsistenz wahren
Naming Conventions
// ✓ Gut: Einheitliche Relation-Codes
'relation' => 'etym'
// ✗ Schlecht: Inkonsistente Schreibweisen
'relation' => 'etymologisch'
'relation' => 'ETYM'Bidirektionalität
// ✓ Gut: Beide Richtungen anlegen (wenn sinnvoll)
createBidirectionalVerweis($word1, $word2, 'etym', 0.7);
// ✗ Vermeiden: Nur eine Richtung (außer bei "part"/"cont")Relation-Codes sinnvoll wählen
// ✓ Gut: Semantisch korrekt
'relation' => 'part' // "venire" ist Teil von "convenire"
// ✗ Schlecht: Falsche Relation
'relation' => 'cont' // Umgekehrt!3. Performance optimieren
Indizes setzen
CREATE INDEX idx_verweise_from ON verweise(from_vocab_id, from_vocab_type);
CREATE INDEX idx_verweise_to ON verweise(to_vocab_id, to_vocab_type);
CREATE INDEX idx_confusion ON verweise(confusion_factor);Selektives Laden
// ✓ Gut: Nur laden, wenn benötigt
if ($needsVerweise) {
$vocab->append('verweise_from');
}
// ✗ Vermeiden: Immer alles laden
$vocab->append(Vocab::APPENDEDFIELDS_VERWEISE);Caching nutzen
// ✓ Gut: Lange Cache-Zeiten für Verweise
Cache::remember("verweise_{$id}", 7200, fn() => $vocab->verweise_all());
// ✗ Vermeiden: Jedes Mal neu abfragen
$verweise = $vocab->verweise_all(); // Bei jedem Request4. Datenpflege
Verwaiste Verweise vermeiden
// Bei Löschung eines Lemmas: Verweise auch löschen (oder soft-deleten)
public function delete()
{
// Soft-Delete der ausgehenden Verweise
DB::table('verweise')
->where('from_vocab_id', $this->id)
->where('from_vocab_type', get_class($this))
->update(['deleted_at' => now()]);
// Soft-Delete der eingehenden Verweise
DB::table('verweise')
->where('to_vocab_id', $this->id)
->where('to_vocab_type', get_class($this))
->update(['deleted_at' => now()]);
parent::delete();
}Duplikate vermeiden
// ✓ Gut: Vor Erstellung prüfen
$existingVerweis = Verweis::where('from_vocab_id', $fromId)
->where('from_vocab_type', $fromType)
->where('to_vocab_id', $toId)
->where('to_vocab_type', $toType)
->first();
if (!$existingVerweis) {
Verweis::create([...]);
}Confusion_factor sinnvoll setzen
// ✓ Gut: Basierend auf Erfahrung/Analyse
'confusion_factor' => 0.75 // Häufig verwechselt
// ✗ Vermeiden: Willkürliche Werte
'confusion_factor' => 0.5 // Immer derselbe Wert5. Dokumentation und Kommentare
Relation begründen
// ✓ Gut: Kommentar bei komplexen Verweisen
Verweis::create([
'from_vocab_id' => $ferre->id,
'to_vocab_id' => $tollere->id,
'form_from' => '1_aktiv.3_perfekt.1_indikativ.1_sg1',
'relation' => 'lemm',
// "ferre" hat suppletive Perfektformen von "tollere" (tuli, tulisti...)
]);Use Cases dokumentieren
/**
* Erstellt Verweise für etymologisch verwandte Komposita
*
* @param Verb $baseVerb Das Basisverb (z.B. "venire")
* @param array $composita Array von Komposita (z.B. ["convenire", "advenire"])
*/
function createCompositaVerweise(Verb $baseVerb, array $composita) { ... }6. Testing
Unit Tests für Verweise
public function test_verweis_creation()
{
$verb1 = Verb::factory()->create();
$verb2 = Verb::factory()->create();
$verweis = Verweis::create([
'from_vocab_id' => $verb1->id,
'from_vocab_type' => get_class($verb1),
'to_vocab_id' => $verb2->id,
'to_vocab_type' => get_class($verb2),
'relation' => 'etym',
]);
$this->assertDatabaseHas('verweise', [
'from_vocab_id' => $verb1->id,
'to_vocab_id' => $verb2->id,
]);
}Feature Tests für Accessor-Methoden
public function test_verweise_from_accessor()
{
$verb = Verb::factory()->create();
$target = Verb::factory()->create();
Verweis::create([
'from_vocab_id' => $verb->id,
'from_vocab_type' => get_class($verb),
'to_vocab_id' => $target->id,
'to_vocab_type' => get_class($target),
]);
$verweise = $verb->verweise_from;
$this->assertCount(1, $verweise);
$this->assertEquals($target->id, $verweise->first()->to_vocab->id);
}Zusammenfassung
Das Verweissystem des Hermeneus-Glossariums ist ein flexibles, polymorphes System zur Abbildung von Beziehungen zwischen lateinischen Lemmata. Die wichtigsten Merkmale:
- Polymorphe Struktur: Wortartübergreifende Verweise möglich
- Formverweise: Spezifische Formen können verknüpft werden
- Typisierte Relationen: Semantische Bedeutung der Beziehung
- Verwechslungsgefahr: Quantifizierung für Übungen
- Accessor-Methoden: Einfacher Zugriff über Vocab-Models
- Soft Deletes: Nicht-destruktive Löschung
- Hybridansatz: Kombination mit Inline-JSON-Formen möglich
Weiterführende Dokumentation:
Letzte Aktualisierung: 2025-11-05