Skip to content

Verweissystem des Glossariums

Inhaltsverzeichnis

  1. Übersicht
  2. Datenmodell
  3. Verweis-Model
  4. Verweis-Typen (Relationen)
  5. Formverweise
  6. Alternativformen: Zwei Ansätze
  7. Accessor-Methoden in Vocab
  8. hasVerweise-Trait
  9. Polymorphe Beziehungen
  10. Verwendungsbeispiele
  11. Verwechslungsgefahr (confusion_factor)
  12. Verwendung in der Applikation
  13. 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

sql
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

FeldTypNullableBeschreibung
idBIGINT UNSIGNEDNeinPrimärschlüssel, Auto-Increment
from_vocab_idBIGINT UNSIGNEDNeinID des Quell-Lemmas (von wo der Verweis ausgeht)
from_vocab_typeVARCHAR(255)NeinVollständige Model-Klasse des Quell-Lemmas (z.B. App\Models\Verb)
to_vocab_idBIGINT UNSIGNEDNeinID des Ziel-Lemmas (worauf verwiesen wird)
to_vocab_typeVARCHAR(255)NeinVollständige Model-Klasse des Ziel-Lemmas
form_fromVARCHAR(255)JaOptionaler Pfad zu einer spezifischen Form im Quell-Lemma (z.B. 1_aktiv.3_perfekt.1_indikativ.1_sg1)
form_toVARCHAR(255)JaOptionaler Pfad zu einer spezifischen Form im Ziel-Lemma
relationVARCHAR(50)JaArt der Beziehung (siehe Verweis-Typen)
confusion_factorFLOATJaVerwechslungsgefahr zwischen 0 und 1 (für Übungen)
created_atTIMESTAMPJaErstellungszeitpunkt (Laravel-Standard)
updated_atTIMESTAMPJaLetzte Aktualisierung (Laravel-Standard)
deleted_atTIMESTAMPJaSoft-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:

sql
-- 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
<?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:

php
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:

php
// 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:

php
$relation = $verweis->relation; // "etym"
$beschreibung = Verweis::RELATION_DESCRIPTION[$relation];
// => "ist etymologisch verwandt mit"

Verwendete Traits

TraitZweck
SoftDeletesErmöglicht Soft-Delete-Funktionalität
VerifiableValidierung der Verweis-Daten (spezifisch für Glossarium)
hasReadableDatesStellt 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

CodeBeschreibungVerwendung
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:

php
// "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:

php
// "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:

php
// "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:

php
// "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:

php
// 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. caussacausa)

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_pl3

Nomina/Adjektive

1_sg / 2_pl
  └─ 1_nom / 2_gen / 3_dat / 4_akk / 5_vok / 6_abl
      └─ (bei Adjektiven) 1_mask / 2_fem / 3_neutr

Praktisches 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

php
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:

php
// 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:

php
// "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

json
{
  "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:

php
// 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

php
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:

php
$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 essefore)
  • Alternativformen mit hoher Verwechslungsgefahr
  • Polymorphe Verweise (Verb → Nomen)
  • Übungsgenerierung

Entscheidungsmatrix: Wann welcher Ansatz?

KriteriumInline JSONVerweis-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:

  1. Inline: Einfache, häufige Formvarianten ohne semantische Bedeutung
  2. Verweis-Eintrag: Komplexe, semantisch relevante Alternativformen oder solche mit Verwechslungsgefahr

Beispiel:

php
// 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

php
/**
 * 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

  1. Abfrage der verweise-Tabelle nach from_vocab_id und from_vocab_type
  2. Für jeden Verweis wird das Ziel-Lemma geladen und als to_vocab hinzugefügt
  3. Rückgabe als Laravel Collection

Verwendung

php
$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

php
// 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

php
/**
 * 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

  1. Abfrage der verweise-Tabelle nach to_vocab_id und to_vocab_type
  2. Für jeden Verweis wird das Quell-Lemma geladen und als from_vocab hinzugefügt
  3. Rückgabe als Laravel Collection

Verwendung

php
$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

php
/**
 * 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

  1. Abfrage aller Verweise, die auf dieses Lemma zeigen
  2. Rückgabe als Key-Value-Paare: [form_to => form_from]
  3. Mapping für Frontend-Verwendung optimiert

Verwendung

php
$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:

php
const APPENDEDFIELDS_VERWEISE = ['verweise_to', 'verweise_to_formen', 'verweise_from'];

Um Verweise in einem Query automatisch zu laden:

php
$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
<?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).

php
/**
 * 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:

php
$verb = Verb::find(1);
$lemmaVerweise = $verb->verweise_from();
// Nur allgemeine Verweise, keine formspezifischen

2. verweise_to()

Zweck: Liefert eingehende Verweise ohne Formverweise.

php
/**
 * 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:

php
$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.

php
/**
 * 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:

php
$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.

php
/**
 * 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:

php
// 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']; // Formverweise

Use 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:

php
class Verb extends Vocab
{
    use hasVerweise;
    // ...
}

Dadurch stehen alle Methoden automatisch zur Verfügung:

php
$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:

  1. *_vocab_id: Die ID des Lemmas
  2. *_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

php
// "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

php
// "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:

php
// 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):

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

php
// 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

php
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

php
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)

php
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

php
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)

php
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)

php
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

php
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)

php
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

WertBedeutungVerwendung
0.0 - 0.2Sehr geringe VerwechslungsgefahrEntfernte semantische Beziehungen
0.2 - 0.4Geringe VerwechslungsgefahrThematisch verwandt, aber klar unterscheidbar
0.4 - 0.6Mittlere VerwechslungsgefahrÄhnliche Bedeutung oder Form
0.6 - 0.8Hohe VerwechslungsgefahrHäufig verwechselte Wörter
0.8 - 1.0Sehr hohe VerwechslungsgefahrFast identische Form oder Bedeutung

Verwendung in Übungen

Der confusion_factor wird primär in Übungen genutzt:

Use Case 1: Übung "Bedeutungen zuordnen"

php
// Ü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"

php
// Formverweise mit hoher Verwechslungsgefahr
$confusingForms = Verweis::whereNotNull('form_from')
    ->where('confusion_factor', '>', 0.6)
    ->get();

Use Case 3: Adaptive Lernsysteme

php
// Häufiger abfragen, wenn Verwechslungsgefahr hoch
$learningWeight = $verweis->confusion_factor * 2;
// Höherer Wert = häufigeres Wiederholen in Lerneinheiten

Beispiele für confusion_factor-Werte

Beispiel 1: finis, is m./f.

php
// "finis" (m.) = Grenze vs. "finis" (f.) = Ende
// SEHR hohe Verwechslungsgefahr (identisches Lemma, verschiedene Bedeutungen)
'confusion_factor' => 0.95

Beispiel 2: venire vs. convenire

php
// Ähnliche Form, verwandte aber unterschiedliche Bedeutung
'confusion_factor' => 0.65

Beispiel 3: amare vs. odisse

php
// Antonyme, semantisch verwandt, aber klar unterscheidbar
'confusion_factor' => 0.2

Beispiel 4: coepi vs. incepi

php
// Alternativformen, mittlere Verwechslungsgefahr
'confusion_factor' => 0.4

Berechnung des confusion_factor

Es gibt keine automatische Berechnung. Der Wert wird manuell oder heuristisch festgelegt basierend auf:

  1. Morphologische Ähnlichkeit: Wie ähnlich sind die Formen?
  2. Semantische Nähe: Wie verwandt sind die Bedeutungen?
  3. Didaktische Erfahrung: Werden die Wörter tatsächlich häufig verwechselt?
  4. 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"

php
// 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"

php
// 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

vue
<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

vue
<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:

php
$verbs = Verb::all();

foreach ($verbs as $verb) {
    $verweise = $verb->verweise_from;  // N+1 Problem!
}

Lösung 1: Eager Loading vermeiden

php
// Lade Verweise nur bei Bedarf
$verb = Verb::find(1);
$verb->append('verweise_from');

Lösung 2: Explizite Abfrage mit JOIN

php
$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

php
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:

php
// 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 (essefore)
  • Wenn confusion_factor relevant ist (Übungen)
  • Polymorphe Beziehungen (wortartübergreifend)
  • Wenn bidirektionale Navigation erwünscht ist

2. Konsistenz wahren

Naming Conventions

php
// ✓ Gut: Einheitliche Relation-Codes
'relation' => 'etym'

// ✗ Schlecht: Inkonsistente Schreibweisen
'relation' => 'etymologisch'
'relation' => 'ETYM'

Bidirektionalität

php
// ✓ 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

php
// ✓ Gut: Semantisch korrekt
'relation' => 'part'  // "venire" ist Teil von "convenire"

// ✗ Schlecht: Falsche Relation
'relation' => 'cont'  // Umgekehrt!

3. Performance optimieren

Indizes setzen

sql
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

php
// ✓ Gut: Nur laden, wenn benötigt
if ($needsVerweise) {
    $vocab->append('verweise_from');
}

// ✗ Vermeiden: Immer alles laden
$vocab->append(Vocab::APPENDEDFIELDS_VERWEISE);

Caching nutzen

php
// ✓ 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 Request

4. Datenpflege

Verwaiste Verweise vermeiden

php
// 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

php
// ✓ 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

php
// ✓ Gut: Basierend auf Erfahrung/Analyse
'confusion_factor' => 0.75  // Häufig verwechselt

// ✗ Vermeiden: Willkürliche Werte
'confusion_factor' => 0.5  // Immer derselbe Wert

5. Dokumentation und Kommentare

Relation begründen

php
// ✓ 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

php
/**
 * 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

php
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

php
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:

  1. Polymorphe Struktur: Wortartübergreifende Verweise möglich
  2. Formverweise: Spezifische Formen können verknüpft werden
  3. Typisierte Relationen: Semantische Bedeutung der Beziehung
  4. Verwechslungsgefahr: Quantifizierung für Übungen
  5. Accessor-Methoden: Einfacher Zugriff über Vocab-Models
  6. Soft Deletes: Nicht-destruktive Löschung
  7. Hybridansatz: Kombination mit Inline-JSON-Formen möglich

Weiterführende Dokumentation:


Letzte Aktualisierung: 2025-11-05