Zum Inhalt springen

Formular mit zusätzlichen (nicht zum Model gehörenden) Feldern

Erstellt am 12. Dezember 2013 · 9 Antworten · letzte Antwort am 6. Januar 2014

Tags: Fluid, Frage

Unbekannter Benutzer ·

Hallo. Ich hänge mal wieder an einer Stelle und hoffe, das mir jemand von euch weiter helfen kann. Ich bin noch dabei, mich in extbase reinzuarbeiten. Bei folgendem Beispiel, dass ich mir zum Einarbeiten ausgesucht habe, komme ich nun nicht mehr weiter (ich verwende Typo3 6.2 beta2):

Ich möchte eine Newsletter-Anmeldung realisieren. Wenn sich ein Nutzer für einen Newsletter anmeldet, wird ein Eintrag in einer Newsletter-Tabelle für ihn angelegt. Wenn sich der Nutzer abmelden möchte, wird er aus der Tabelle gelöscht. In der Tabelle sind also nur die Nutzer, die einen Newsletter wollen. Mein Model besitzt entsprechend nur die Eigenschaften "email", "registrierDatum", "bestaetigungsDatum" und die üblichen Typo3-Felder.
Es gibt nun ein Formular, in welches man die E-Mail-Adresse einträgt und dann auswählen soll, ob man sich an- oder abmelden möchte (mit Radio-Buttons). Die beiden Informationen für die Datumsangeben werden intern gesetzt, spielen hier also keine Rolle.

Nun zum Problem:
Es handelt sich bei den Radiobuttons "anmelde/abmelden" nicht um Eigenschaften, die zum Model gehören. Da ich sowohl im Formular als auch in den verarbeitenden Aktionen (edit und save) als Parameter ein Objekt erwarte, das dem oben genannten Model entspricht, erhalte ich beim Senden des Formulars den Fehler:
Exception while property mapping at property path ""😛roperty "register_action" was not found in target object of type "XY\Newsletter\Domain\Model\Newsletter"

Meine Frage:
Wie gehe ich mit einem Formular um, wenn ich Model-fremde Felder einfüge? Mein Ziel ist es, dass das Objekt trotzdem über den Validator anhand der Angaben im Model geprüft wird.

Ich habe bisher eine Lösung gesehen, in welcher die Model-fremden Eigenschaften einfach mit ins Model aufgenommen wurden (ohne die Zuordnung zu einem Datenbankfeld). Aber das finde ich recht unsauber und kann irgendwie nicht Sinn der Sache sein.

Dann habe ich folgende Möglichkeit gefunden: http://blog.sebastiaandejonge.com/articles/2013/january/17/form-validation-of-non-domain-model-properties-with-extbase/
Die sieht aber ziemlich umständlich aus und ich wüsste nicht, wie sie das Problem mit der oben genannten Fehlermeldung beheben soll (ich komme ja nicht mal bis zum Validieren).

Ansonsten würde mir nur noch einfallen, das Formular ohne Zuordnung zu einem Objekt/Model zu senden und die request-Daten in einem eigenen Validator abzuarbeiten. Das dürfte aber ebenfalls unsauber sein und mir fehlt die Objekt-Zuordnung, weshalb ich die Eigenschaften nicht mehr anhand der Kommentare im Model validieren lassen kann.

Wie löst man so ein Problem richtig und sauber? (Ein anderes Beispiel für so einen Fall wäre auch das Einfügen weiterer Felder aufgrund von Spamschutz - z.B. Honeypot, Timestamp, Captcha, etc. - all diese Daten hätten auch nichts mit einem bestimmten Objekt zu tun).
Wäre wirklich dankbar für Vorschläge oder Tipps!

Schweriner · · Beste Antwort

Schau Dir mal dazu am Besten die sog. blog_example Extension an. Dort gibt es eine Edit Action mit PostForm Partial zum Updaten von Blogposts. So würde ich es erstmal auch probieren.

Unbekannter Benutzer ·

Also dank folgender Seite konnte ich zumindest das Problem mit dem Property-Mapping (die Fehlermeldung) beheben:
http://www.muenster-webdesign.net/blog/typo3fluid-verschiedene-models-ueber-ein-formular-bedienen/

Meine Controller-Action sieht nun also so aus:
public function saveAction(\XY\Newsletter\Domain\Model\Newsletter $newsletter, $register_action) {
...
}
Bei meinen zusätzlichen (vom Model unabhängigen) Radio-Buttons "register_action" habe ich statt dem Attribut "property" das Attribut "name" genommen:
<f:form.radio name="register_action" value="1" checked="{register_action}==1" class="checkbox" />
--> dadurch wird das Feld nicht mehr auf das Objekt gemappt

Ich kann nun in meiner saveAction auch auf das Objekt und auf das zusätzliche Feld zugreifen.

Es bleibt aber zum Einen immer noch die Frage mit dem Validator und zum Anderen habe ich nun das Problem, dass bei einer fehlerhaften Eingabe (wobei ja das Formular nochmal dargestellt wird mit der Fehlermeldung) der Wert für "register_action" nicht mit zur editAction übergeben wird. Egal welchen Radio-Button ich gewählt habe: er nimmt den Standardwert, den ich im Kopf der editAction angegeben habe:

public function editAction(\XY\Newsletter\Domain\Model\Newsletter $newsletter = NULL, $register_action = 1) {
...
}

Beim Absenden ohne Fehler (also wenn das Formular korrekt gefüllt wurde), erhalte ich aber die richtigen Werte in der saveAction.

Eine Idee?
(P.S.: an den Werten 0 und 1 in den Radio-Buttons kann es nicht liegen, denn ich hatte auch schon zum Testen die Werte 2 und 3 genommen bzw. String-Werte und das Verhalten blieb gleich)

Unbekannter Benutzer ·

Die blog_example-Erweiterung habe ich mir angeschaut inkl. der editAction und updateAction von Blog und Blogpost. Die Beispiele entsprechen leider nicht meiner Problemstellung, da hier keine modelfremden Werte übergeben und verarbeitet/validiert werden.

Folgende Fragen sind jetzt im Grunde für mich noch offen:

1. Frage
Warum wird der Wert des Model-fremden Feldes "register_action" bei einer fehlerhaften Formulareingabe nicht mit in das Bearbeiten-Formular übernommen bzw. in die editAction übergeben? (Die Werte für das Newsletter-Objekt werden übernommen, nur nicht das zusätzliche Feld > vgl. voriger Post)

2. Frage
Ich würde das Newsletter-Objekt gern komplett als Objekt im Controller-Argument mit einem Validator überprüfen und benötige dabei in dem Validator noch Zugriff auf das zusätzlich gesendete Feld "register_action". Wie kann ich aus dem Validator, mit dem ich das Newsletter-Objekt prüfe, auf das Feld bzw. auf das request-Objekt zugreifen? Wenn ich das request-Objekt mit new instanziere, ist das Objekt logischerweise leer. Aber auch bei der Einbindung mit inject ist das Objekt leer. Der Zugriff auf $_POST ist problemlos im Validator möglich, aber sicherlich nicht die feine Art.

3. Frage
Wie ist eigentlich die Reihenfolge der Validatoren-Prüfung bzw. kann ich diese beeinflussen? Wird zuerst mein eigener Validator ausgeführt, den ich bei der Action zur Prüfung des Controller-Argumentes "newsletter" nutze oder werden zuerst über die normalen extbase-Validatoren die Eigenschaften im Model geprüft (z.B. ist die E-Mail-Adresse leer oder ungültig?)?

Hintergrund von Frage 3:
Ich möchte in meinem Validator ermitteln, wie der aktuelle Status der E-Mail-Adresse ist (bereits registriert, nicht vorhanden, nicht bestätigt, ...) und anhand dessen prüfen, ob die gewünschte Aktion erlaubt ist. (Wenn die E-Mail-Adresse z.B. nicht registriert ist, kann sie nicht abgemeldet werden für den Newsletter > Aktion ist ungültig). Die ganze Prüfung in meinem eigenen Validator macht aber nur Sinn, wenn es sich überhaupt um eine gültige übergebene E-Mail-Adresse handelt. Ist die E-Mail-Adresse leer oder fehlerhaft, brauch ich nicht weiter prüfen. Daraus folgt dann noch die nächste Frage:

4. Frage
Kann ich irgendwie in meinem eigenen Validator prüfen, ob bereits Fehler von anderen Validatoren gemeldet wurden?

Das sind nun zwar einige Fragen, die teilweise nicht unbedingt etwas mit der Themen-Überschrift zu tun haben, aber sie hängen damit zusammen und ich wollte auch nicht 4 neue Themen erstellen.
So schön die Idee hinter Extbase und Fluid auch ist: das ganze ist doch ziemlich komplex und wirft leider immer wieder viele Fragen auf. Ich hoffe ihr könnt mir ein paar davon beantworten :-)

Schweriner ·

Hab leider gerade nicht die Zeit mich jetzt in all deine Fragen reinzudenken, aber zu Frage 1: Könntest Du nicht einfach in deinem Controller via assignMultiple neben dem Newsletter Objekt auch noch die RequestDaten an den View übergeben? Dann solltest Du doch drauf zugreifen können.

Unbekannter Benutzer ·

Danke, dass du dir trotzdem die Zeit genommen hast :-)
Ich bin mir gerade nicht sicher, ob überhaupt der korrekte Wert per Request bei einer fehlerhaften Eingabe in die editAction zurückgegeben wird (ich hatte nur den Parameter getestet - nicht die Request-Daten selbst). Das kann ich aber leider auch erst wieder am Montag testen. Werde ich aber auf jeden Fall mal versuchen!

Unbekannter Benutzer ·

So, ich habe mal getestet, wie sich $_POST und das Request-Objekt in meiner editAction verhalten, wenn ich eine fehlerhafte Formulareingabe durchführe. Ergebnis:
In $_POST befinden sich alle gesendeten Informationen. $this->request->getArguments() ist ein leeres Array. Über das Request-Objekt komme ich also leider nicht an den Wert des zusätzlichen Feldes und eine Lösung direkt mit $_POST scheint mir nicht wirklich sauber (da in Extbase so großer Wert auf Kapselung gelegt wird). Das Newsletter-Objekt wird aber weiterhin problemlos an die editAction zurück gegeben.
Ist dieses komische Verhalten von Extbase wirklich so gewollt oder mache ich hier irgendwo einen Fehler? Die saveAction funktioniert problemlos!

Unbekannter Benutzer ·

Nach einigem Suchen und Rumprobieren kann ich mir die Fragen nun einigermaßen selbst beantworten. Für die, die es interessiert hier noch die Antworten:

zur 1. Frage
Das "Warum" für die Frage ist zwar für mich immer noch nicht geklärt, aber ich greife nun in meiner editAction einfach auf folgenden Wert zu:
\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('tx_newsletter_pi1')["register_action"]
Ist vielleicht nicht die beste Lösung, aber besser als direkt auf $_POST zuzugreifen.
Hier noch ein Link zu den wichtigsten Funktionen von GeneralUtility (hat mir an der Stelle geholfen):
https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Index.html

zur 2. Frage
Dieses Problem habe ich ebenfalls mit dem Zugriff auf
\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('tx_newsletter_pi1')["register_action"]
gelöst.

zur 3. Frage
Die Reihenfolge habe ich nun einfach mal manuell getestet. Ergebnis:
Zuerst wird mein eigener Validator ausgeführt (also der, der im Controller zum Prüfen der übergebenen Argumente angegeben wurde).
Erst danach werden die Validatoren ausgeführt, die im Model angegeben wurden. (Ob das immer so ist, weiß ich allerdings nicht.)
Ich vermute mal, dass man die Reihenfolge nicht beeinflussen kann, weshalb ich in meinem eigenen Validator nun doch selbst erstmal prüfen muss, ob die E-Mail-Adresse valide ist (vgl. #116881).

zur 4. Frage
Da mein Validator offensichtlich VOR den Validatoren aus dem Model aufgerufen wird, hat sich die Frage für mich erübrigt.

Es darf gern kommentiert werden, ob die Antworten/Lösungen so in Ordnung sind - ich bin offen für bessere Lösungen und lasse mich gern eines Besseren belehren! 😉

harald1972 ·

Hallo,
zu dem Punkt vor deinen Fragen...
Wenn du eine Checkbox (oder Radio-Button) für eine boolean-Property darstellen willst, kommt es zu einem Bug; der aktuelle ExtensionBuilder sollte aber schon einen passenden Workaround erzeugen.
Er macht das natürlich nicht, wenn du hinterher etwas externes einfügst.
Ich hatte neulich sowas ähnliches, das dann auch via GeneralUtility gelöst wird... Stichwort: fluid bug ##5636.

zur 1.Frage
Da kann ich zwar nur raten, aber bist du sicher, daß dein non-property Wert auch immer und jedesmal mitgeschleppt wird?
Wenn du Partials verwendest, müssen diese jeden relevanten Wert erhalten.

Unbekannter Benutzer ·

Hallo und danke für die Antwort.
Das mit dem Bug ist gut zu wissen, aber da es sich nicht um eine Eigenschaft des Models handelt, betrifft mich das an dieser Stelle nicht.

Die Eigenschaft übergebe ich dem Template via assign. Die Daten werden auch korrekt vom Template in die Partials-Datei übergeben. Es hängt definitiv an der Übergabe der Werte beim automatischen Aufruf der editAction bei einem Fehler. Deshalb vermute ich einen Bug innerhalb von Extbase. Vielleicht wird das ja bis zu der stable-Version von Typo3 6.2 noch behoben... Mit der Globalen \TYPO3\CMS\Core\Utility\GeneralUtility::_GP funktioniert es ja erstmal.