Skip to content

Filament-Formular speichert nicht: Ursache sauber eingrenzen

Ein einzelnes Feld bleibt nach dem Speichern alt, obwohl Filament keinen Fehler meldet. Mit einer Prüfung entlang des Datenwegs findest du heraus, ob Formularzustand, Hook, Eloquent-Modell, Relation oder Anzeige die Ursache ist.

Moritz Klaßen

Moritz Klaßen

Entwickler & Gründer von Klassen AI

9 Min. Lesezeit

Wenn Filament nach dem Speichern eine Erfolgsmeldung zeigt, hat es die sichtbaren Formularwerte korrekt in die Datenbank geschrieben. Diese Annahme ist falsch. Die Meldung bestätigt je nach Umsetzung lediglich, dass die Aktion ohne offen behandelte Ausnahme beendet wurde. Zwischen Eingabefeld und erneuter Anzeige liegen mehrere Verarbeitungsschritte, an denen ein Wert verändert, ausgelassen oder aus einer anderen Quelle gelesen werden kann.

Deshalb solltest du bei diesem Fehler nicht zuerst Formularkomponenten austauschen, Caches leeren oder den Save-Button verdächtigen. Verfolge stattdessen einen einzelnen Wert vom Formularzustand bis zur Datenbank und wieder zurück zur Anzeige. An der ersten Stelle, an der erwarteter und tatsächlicher Wert voneinander abweichen, sitzt die Ursache.

Trenne zuerst die unterschiedlichen Fehlerbilder

„Das Formular speichert nicht“ ist als Fehlerbeschreibung zu ungenau. Für eine belastbare Analyse musst du feststellen, welcher Teil des Speichervorgangs tatsächlich scheitert.

  • Es erscheint keine Erfolgsmeldung: Die Aktion läuft möglicherweise nicht durch, eine Validierung blockiert oder eine Ausnahme beendet die Anfrage.
  • Die Erfolgsmeldung erscheint, aber die Datenbank enthält den alten Wert: Der Wert fehlt im Speicherdatensatz, wird vorher verändert oder vom Modell nicht übernommen.
  • Die Datenbank enthält den neuen Wert, Filament zeigt aber den alten: Der Fehler liegt auf dem Rückweg, etwa in einer Abfrage, einem Accessor, einer Relation oder der Darstellung.
  • Nur ein bestimmtes Feld ist betroffen: Prüfe die Konfiguration und Verarbeitung dieses Feldes, statt das gesamte Formular umzubauen.
  • Nur einzelne Datensätze oder Benutzer sind betroffen: Dann werden Bedingungen, Mandantenbezug, Modellzustand oder unterschiedliche Abfragen relevant.
  • Das Anlegen funktioniert, das Bearbeiten nicht: Erstell- und Bearbeitungsseite können unterschiedliche Hooks, Regeln und Aktionen verwenden.

Diese Trennung spart Zeit, weil du nicht gleichzeitig Frontend, Modell und Datenbank untersuchen musst. Ein grüner Hinweis oben rechts ist dabei ein Indiz, aber noch kein Datenbankbeleg.

Lege einen kontrollierten Testfall fest

Nimm einen Datensatz, dessen ID du kennst, und ändere genau ein Feld auf einen eindeutig erkennbaren Wert. Bei einem Feld Status eignen sich vorhandene gültige Werte. Bei einer internen Notiz kannst du einen kurzen Testtext verwenden, sofern darin keine sensiblen Daten landen.

Halte vor dem Test vier Angaben fest:

  • die ID des Datensatzes,
  • den bisherigen Wert,
  • den erwarteten neuen Wert,
  • den angemeldeten Benutzer beziehungsweise den aktiven Mandanten, falls das Adminpanel mandantenfähig ist.

Ändere während dieser Prüfung keine weiteren Felder. Sonst weißt du später zwar, dass irgendetwas passiert ist, aber nicht mehr genau was. Das ist Debugging nach Wetterlage.

Prüfe nach dem Speichern den Datensatz direkt in der Datenbank. Achte darauf, dass du dieselbe Umgebung, Verbindung und Tabelle untersuchst, die das Adminpanel verwendet. Eine lokale Datenbank zu betrachten, während der Fehler auf dem Staging-System auftritt, liefert sehr ordentliche Antworten auf die falsche Frage.

Prüfe den Formularzustand vor dem Speichern

Filament verwaltet die Werte eines Formulars als Zustand. Bevor daraus ein Datensatz für das Modell wird, kann dieser Zustand verändert oder teilweise ausgeschlossen werden. Filament bezeichnet die Übergabe eines Feldwerts an die weitere Verarbeitung als Dehydration. Ein sichtbarer Wert muss deshalb nicht automatisch Bestandteil der Speicherdaten sein.

Deaktivierte und bedingt sichtbare Felder

Ein deaktiviertes Feld kann absichtlich von der Speicherung ausgeschlossen sein. Das ist sinnvoll, wenn ein Wert nur angezeigt werden soll. Problematisch wird es, wenn du das Feld optisch deaktivierst, aber erwartest, dass sein Wert beim Speichern erneut übertragen wird.

Auch Sichtbarkeit und Speicherung sind getrennte Fragen. Ein Feld kann abhängig von einem anderen Feld ausgeblendet werden, während sein alter Zustand erhalten bleibt. Umgekehrt kann eine Zustandsänderung den Wert beim Ausblenden leeren. Prüfe deshalb die Konfiguration des betroffenen Feldes auf Bedingungen für Sichtbarkeit, Deaktivierung und Dehydration.

Abhängige und reaktive Felder

Bei abhängigen Auswahlfeldern setzen Callbacks häufig andere Felder zurück. Wählst du beispielsweise eine neue Kategorie, kann die bisherige Unterkategorie geleert werden. Läuft diese Logik auch während der Initialisierung oder kurz vor dem Speichern, verschwindet ein zuvor sichtbarer Wert unerwartet.

Untersuche bei solchen Feldern die Reihenfolge der Zustandsänderungen. Entscheidend ist der Wert unmittelbar vor der Speicherung, nicht der Wert, den du einige Sekunden zuvor im Browser gesehen hast.

Abweichende Feld- und Attributnamen

Der Zustandsbezeichner eines Feldes muss zu dem Ziel passen, in das du speichern möchtest. Ein Feld namens contact.email beschreibt einen verschachtelten Zustand. Ein einfaches Modellattribut email wird dadurch nicht automatisch aktualisiert. Dasselbe gilt für umbenannte Datenbankspalten, JSON-Pfade und Felder, die nur für die Oberfläche berechnet werden.

Wenn genau ein Feld ausfällt, vergleiche seinen Namen mit funktionierenden Feldern. Kleine Abweichungen bei Zustandswegen sind unspektakulär und deshalb erstaunlich ausdauernd.

Verfolge den Wert durch Validierung und Hooks

Nach dem Auslesen des Formularzustands kann die Anwendung die Daten normalisieren. Dazu gehören das Entfernen leerer Werte, die Umwandlung von Datumsangaben oder das Ableiten eines Status. Diese Schritte können in Filament-Hooks, benutzerdefinierten Aktionen oder allgemeinen Hilfsmethoden stecken.

Prüfe alle Stellen, die vor dem Erstellen oder Speichern eines Datensatzes laufen. Je nach Aufbau und Filament-Version heißen die konkreten Methoden unterschiedlich. Relevant sind vor allem Hooks und Aktionen, die Formulardaten als Array entgegennehmen und verändert zurückgeben.

Typische Ursachen sind:

  • Ein Hook gibt nur ausgewählte Felder zurück und vergisst das neue Feld.
  • Ein leerer Wert wird pauschal entfernt, obwohl er eine bestehende Angabe löschen sollte.
  • Ein Status wird aus anderen Feldern neu berechnet und überschreibt die Eingabe.
  • Ein Datumswert wird in ein unerwartetes Format umgewandelt.
  • Eine benutzerdefinierte Speicheraktion verwendet nicht den aktuellen Formularzustand.

Protokolliere für die Fehlersuche nur die benötigten Angaben: Datensatz-ID, Feldname, erwarteter Wert und Verarbeitungsphase. Passwörter, Tokens, vollständige Formulare und personenbezogene Inhalte gehören nicht ins Log. Für die Analyse eines Statusfeldes reicht dessen Statuswert; der Lebenslauf des dazugehörigen Kontakts hilft nicht weiter.

Kontrolliere, was das Eloquent-Modell übernimmt

Kommt der richtige Wert bis zum Modell, ist der nächste Prüfpunkt Laravel Eloquent. Das ist die Schicht, die Modellattribute in Datenbankwerte übersetzt und speichert.

Massenzuweisung und geschützte Attribute

Werden mehrere Attribute gemeinsam an ein Modell übergeben, greifen die Regeln für Massenzuweisung. Ein neues Feld kann fehlen, wenn es nicht als zuweisbar vorgesehen oder ausdrücklich geschützt ist. Abhängig von der Laravel-Konfiguration kann sich das als Ausnahme zeigen oder dazu führen, dass das Attribut nicht wie erwartet übernommen wird.

Vergleiche das betroffene Attribut mit einem funktionierenden Feld desselben Modells. Prüfe außerdem, ob die Datenbankmigration tatsächlich ausgeführt wurde und die Spalte in der untersuchten Umgebung vorhanden ist.

Casts, Mutatoren und Accessoren

Casts wandeln Modellwerte zwischen PHP und Datenbankformat um. Sie sind etwa für boolesche Werte, Datumsangaben oder JSON-Strukturen üblich. Ein unpassender Cast kann einen korrekten Formularwert anders speichern als erwartet.

Ein Mutator verändert ein Attribut vor dem Schreiben. Ein Accessor bereitet es beim Lesen auf. Wenn die Datenbank einen korrekten Wert enthält, Filament aber etwas anderes zeigt, ist besonders der Accessor relevant. Prüfe dabei immer den Rohwert in der Datenbank und den vom Modell gelesenen Wert getrennt.

Observer, Events und spätere Aktualisierungen

Model Observer und Event Listener können nach einer Änderung weitere Attribute setzen. Ein Statuswechsel kann beispielsweise eine Berechnung auslösen, die den Status aufgrund anderer Bedingungen wieder zurücksetzt. Auch eine nachgelagerte Aufgabe kann einen Wert kurz nach dem Speichern überschreiben.

Falls der neue Wert zunächst in der Datenbank erscheint und später verschwindet, suche nicht länger im Formular. Prüfe zeitversetzte Aufgaben, Listener, Importe und andere Prozesse, die dasselbe Modell aktualisieren.

Behandle Relationsfelder als eigenen Speicherweg

Repeater, Mehrfachauswahlen und andere Relationsfelder speichern ihre Daten häufig nicht in der Tabelle des Hauptmodells. Die Werte können in einer verknüpften Tabelle oder einer Zwischentabelle liegen. Ein Blick auf die Haupttabelle reicht dann nicht aus.

Prüfe bei einem Relationsfeld drei Dinge:

  1. Ist die Relation im Modell korrekt definiert?
  2. Verwendet die Formularkomponente tatsächlich diese Relation?
  3. Existieren die erwarteten Zeilen beziehungsweise Verknüpfungen nach dem Speichern?

Besonders bei wiederholbaren Unterformularen kann der Hauptdatensatz erfolgreich gespeichert werden, während die erwarteten Kinddaten aus einem anderen Grund fehlen. Behandle Hauptmodell und Relation deshalb als getrennte Übergaben. So erkennst du, ob der Fehler im übergeordneten Formular oder beim Synchronisieren der Beziehung entsteht.

Wenn die Datenbank stimmt, untersuche die Anzeige

Steht der neue Wert korrekt in der Datenbank, ist weiteres Experimentieren mit der Speicheraktion Zeitverschwendung. Jetzt musst du klären, warum Filament beim erneuten Lesen einen anderen Wert verwendet.

Kontrolliere zuerst, ob nach dem Speichern wirklich derselbe Datensatz geladen wird. Bei mandantenfähigen Anwendungen, benutzerdefinierten Routen oder eigenen Record-Auflösungen kann eine identische sichtbare Bezeichnung zu einem anderen Datensatz gehören. Die Primärschlüssel müssen übereinstimmen.

Danach kommen folgende Stellen infrage:

  • Ein Accessor ersetzt den gespeicherten Rohwert durch eine berechnete Darstellung.
  • Die Spalte oder das Formularfeld zeigt ein Attribut aus einer Relation statt aus dem Hauptmodell.
  • Eine benutzerdefinierte Abfrage wählt nicht alle benötigten Spalten aus.
  • Ein globaler Scope verändert, welcher Datensatz geladen wird.
  • Eine Formatierungsfunktion stellt einen Ersatzwert oder eine übersetzte Bezeichnung dar.
  • Der Formularzustand wird nach dem Speichern nicht mit dem frisch geladenen Modell abgeglichen.

Lade die Seite einmal vollständig neu und vergleiche das Ergebnis mit der direkten Datenbankabfrage. Verschwindet der Fehler erst nach dem Neuladen, liegt wahrscheinlich ein veralteter Komponenten- oder Modellzustand vor. Bleibt er bestehen, untersucht du die Abfrage und Darstellung des Feldes.

Nutze feste Prüfpunkte statt vieler Vermutungen

Für Supportfälle eignet sich eine Reihenfolge mit vier Prüfpunkten. Notiere an jedem Punkt den Wert desselben Feldes:

  1. Formular: Welcher Wert befindet sich unmittelbar vor der Speicheraktion im Formularzustand?
  2. Speicherdaten: Welcher Wert wird nach Normalisierung und Hooks an das Modell übergeben?
  3. Datenbank: Welcher Rohwert steht nach dem Speichern in der richtigen Tabelle und Zeile?
  4. Anzeige: Welchen Wert liest und formatiert Filament beim erneuten Laden?

Weicht der Wert zwischen Formular und Speicherdaten ab, prüfst du Feldkonfiguration und Hooks. Weicht er zwischen Speicherdaten und Datenbank ab, untersuchst du Modell, Casts, Mutatoren, Observer und Relationslogik. Stimmen Datenbank und Modellwert, aber die Oberfläche nicht, liegt die Ursache in Abfrage, Zustandsaktualisierung oder Darstellung.

Dieser Ablauf funktioniert auch dann, wenn mehrere technische Schichten beteiligt sind. Du musst dafür nicht das gesamte Adminpanel verstehen. Du brauchst lediglich einen bekannten Datensatz, einen eindeutig verfolgbaren Wert und Zugriff auf die jeweiligen Übergabepunkte.

Vermeide Reparaturen, die nur das Symptom verdecken

Ein zusätzlicher manueller Aufruf zum Speichern kann den Fehler scheinbar beseitigen und gleichzeitig doppelte Modellereignisse auslösen. Ein pauschales Entfernen aller Hooks macht das Formular möglicherweise wieder funktionsfähig, entfernt aber auch fachliche Regeln. Und ein Cache-Reset ist kein belastbarer Fix, wenn du nicht benennen kannst, welcher Cache einen falschen Wert geliefert hat.

Bevor du Code änderst, solltest du deshalb einen Satz vervollständigen können: „Der erwartete Wert geht zwischen diesem und jenem Prüfpunkt verloren.“ Erst dann ist klar, welche Änderung den Fehler behebt und welche Nebenwirkungen du testen musst.

Ergänze anschließend mindestens einen Test für den betroffenen Speicherweg. Bei einem normalen Attribut sollte er nach der Aktion den Datenbankwert prüfen. Bei einer Relation muss er zusätzlich die verknüpften Datensätze oder Einträge der Zwischentabelle kontrollieren. So bleibt aus einem schwer greifbaren Supportfall eine überprüfbare Regel übrig.

Fazit

Wenn ein Filament-Formular scheinbar nicht speichert, ist die Erfolgsmeldung weder Beweis noch Hauptverdächtiger. Entscheidend ist, an welcher Grenze der erwartete Wert verloren geht: im Formularzustand, bei der Aufbereitung, im Eloquent-Modell, in einer Relation oder auf dem Weg zurück zur Anzeige.

Mit einem kontrollierten Datensatz und vier festen Prüfpunkten grenzt du diese Fehlerklasse zuverlässig ein. Das ist weniger spektakulär als ein kompletter Umbau des Formulars. Dafür behebt es die Ursache und nicht nur den Teil, der gerade sichtbar quietscht.

Häufige Fragen

Kurz beantwortet, damit du schneller einschätzen kannst, was für dein Projekt wichtig ist.

Warum zeigt Filament eine Erfolgsmeldung, obwohl ein Wert nicht gespeichert wurde?

Die Meldung zeigt, dass die Speicheraktion ohne offen behandelte Ausnahme beendet wurde. Ein Feld kann vorher aus den Speicherdaten entfernt, durch einen Hook verändert oder später durch Modelllogik überschrieben worden sein.

Werden deaktivierte Filament-Felder automatisch gespeichert?

Darauf solltest du dich nicht verlassen. Deaktivierte Felder können von der Dehydration und damit von den Speicherdaten ausgeschlossen sein. Prüfe die Feldkonfiguration und entscheide ausdrücklich, ob der Wert nur angezeigt oder auch gespeichert werden soll.

Warum steht der richtige Wert in der Datenbank, aber nicht im Filament-Formular?

Dann liegt die Ursache wahrscheinlich beim Lesen oder Anzeigen. Prüfe Accessoren, Relationsfelder, benutzerdefinierte Abfragen, Formatierungen und ob nach dem Speichern wirklich derselbe Datensatz frisch geladen wird.

Wie prüfe ich ein fehlerhaftes Relationsfeld in Filament?

Kontrolliere die Relationsdefinition im Modell, die Anbindung der Formularkomponente und die tatsächlich angelegten Zeilen oder Verknüpfungen. Der Wert muss nicht in der Tabelle des Hauptmodells gespeichert werden.