Hallo,
ich überprüfe in der createAction neue Daten aus meinem Anmeldeformular auf einen speziellen Fall (konkret checke ich, ob der gewünschte Benutzername in der verknüpften fe_users schon vorliegt).
Schlägt die Prüfung fehl, rufe ich die newAction per redirect auf und erhalte mein Formular, inklusive Fehlermeldung (per FlashMessage).
Aber die Felder sind nun leer, alle Eingaben des Kunden waren also umsonst (bei der eigentlichen Validierung auf Pflichtfelder, passende email etc. werden sie ja wieder mit den berits erfassten Daten ausgefüllt).
Im arguments-Parameter von redirect($action,$controller,$extension,$arguments) kann ich ja das Object nicht übergeben.
Und alle Werte per ->getName() an ein Array zu übergeben um das dann wieder per assign in der newAction zu übergeben kann es doch nicht sein?
newAction:
$this->view->assign('newProvider', $this->request->getArgument('provider'));
createAction:
$provider['address1'] = $newProvider->getAddress1();
$provider['address1'] = $newProvider->getAddress2();
$this->redirect('new','Provider',null,array('provider' => $provider));
Also: Das funktioniert, aber dann muss ich alle Formular-Felder-Parameter übergeben, was ja fehlerträchtig und wenig erweiterungsfreudig ist...
Vielleicht hab ich auch was simples übersehen, aber nach diversen Extbase-Problemen und -Grübeleien in dieser Woche raucht mir grade wieder die Birne...
Viele Grüße vom Rhein, Stefan
Hallo Stefan,
ich kann Dir kurz beschreiben, wie ich solche Sachen (Formulare + Validierung) angehe.
Zuerst erstelle ich mir ein Model, das genauso aussieht wie das Formular. In diesem kann ich mit der @validate-Annotation schon mal jede Property für sich testen. Mein Controller hat dann eine indexAction und eine submitAction. Die indexAction zeigt das Formular an, auf die submitAction wird überraschenderweise das Formular geleitet. Schlägt nun eine Validierung fehl, wird automatisch wieder auf die action geleitet, von wo der Aufruf kam, also die indexAction. Um aber nicht in einer Endlos-Validierungsschleife zu enden, muss darüber natürlich mit @dontvalidate $myFormModel die Validierung abgeschaltet werden. Beide Actions bekommen als Paramter (Tx_MyExt_Domain_Model_MyFormModel $myFormModel = NULL). In der indexAction muss das Objekt erzeugt werden, wenn es NULL ist (also der User das erste Mal auf die Seite kommt), und an die View übergeben werden.
Grau ist alle Theorie, deshalb hier mein Controller:
/**
* @param Tx_MyExt_Domain_Model_MyForm $myForm
* @dontvalidate $myForm
*/
public function indexAction(Tx_MyExt_Domain_Model_MyForm $myForm = NULL) {
if ($myForm == NULL) {
$myForm = new Tx_MyExt_Domain_Model_MyForm;
} else {
$formErrors = $this->request->getErrors();
$formErrors = $formErrors['myForm']->getErrors();
$this->view->assign('formErrors', $formErrors);
}
$this->view->assign('myForm', $myForm);
}
/**
* @param Tx_MyExt_Domain_Model_MyForm $myForm
* @validate $myForm Tx_MyExt_Domain_Model_MyFormValidator
*/
public function submitFormAction(Tx_MyExt_Domain_Model_MyForm $myForm = NULL) {
if($myForm === NULL){
$this->redirect('index');
}
// weitere Bearbeitung
}
Zusätzlich validiere ich hier noch im Tx_MyExt_Domain_Model_MyFormValidator, um z.B. Abhängigkeiten zwischen Variablen zu validieren. Deine Prüfung, ob ein Name vorhanden ist, könntest Du dann in einem Validator im Model oder im Tx_MyExt_Domain_Model_MyFormValidator durchführen.
Eine Prüfung nach Gültigkeit von Variablen, bzw. generell Validierung wird nicht im Controller gemacht, denn das ist nicht die Arbeit des Controllers.
Du musst Dir also keine Gedanken machen wie Deine Daten wieder zur indexAction kommen, das macht Extbase alles für Dich.
In Deinen Templates benutzt Du dann
<f:form action="submit" object="{myForm}" name="myForm">
<f:form.textbox property="myProp" />
</f:form>
"name" und "object" muss den gleichen Namen haben.
Sollte ich was vergessen haben, bitte ich um Hinweise. Vielleicht können wir so Einsteigern die Formular-Verarbeitung leicht näher bringen.
Beste Grüße,
Sven
Hallo Sven,
vielen Dank für Deine ausführliche Antwort.
Soweit ist es auch klar, das ist ja eigentlich auch das sinnvollste Vorgehen, dafür haben wir ja unsere Objekte und alles andere validiere ich auch dort.
Mein Problem ensteht ja aber, weil der User zum Login in fe_users seperat angelegt wird.
Ich erstelle also bei der Anmeldung eines Kunden zum einen einen neuen fe_users-Eintrag (über den ich dann später das ganze Usergruppen und Login-Managment abwickle) und zum anderen einen Eintrag als 'Provider' für den Kundeneintrag.
Den Providerteil kann ich also nach Extbase-Standard verarbeiten und validieren, aber den Usernamen muss ich ja seperat auf Doppel testetn, da das nicht Teil des Models ist.
Vielleicht ist mein Kernfehler schon, dass ich nicht fe_users erweitere sondern mit einem eigenen Kunden-Modell operierere. Das schien mir aber wiederum besser zu handeln, wenn es um andere Dinge geht.
Aber vielleicht muss ich doch von dieser Seite ansetzen?
Andererseits ist ja nicht das Prüfen und zurückgehen auf die formularaufrufende action das Problem sondern nur, dass ich da nicht mehr (zumindest nicht in der Extbase gerechtwerdenen Eleganz) auf die Feldwerte zugreifen kann.
Viele Grüße, Stefan
Hi,
ich weiß nicht, ob es noch aktuell ist, aber ich hatte das gleiche Problem und ich lese in der create-Action das POST-Array in ein Array ein und das übergebe ich als Parameter im redirect mit.
$parameter = array();
$parameter = t3lib_div::_POST();
im Formular hole ich mir dann über dieses array die angaben wieder: ..value="{parameter.tx_ext_fe.formularname.name}" ...
viele Grüße
Hallo,
das ist ein Weg um wieder an die Daten zu kommen - aber auch hier muss ich wieder alle Felder im Nachhinein anpassen.
Ich nutze ja wieder nicht die vorhandenen Objektelemente und verlasse damit den Extbaserahmen, oder?
Aber ich muss zumindest bei Änderungen der Felder diese explizit raussuchen, weil ich alle erreiche - aber habe auch den ganzen POST-Sumpf drin.
Aber Danke für den Ansatz.
Viele Grüße, Stefan
wenn du eine andere Lösung gefunden hast, das Objekt zu übergeben, kannst du ja posten - würde mich auch interessieren. So rein theoretisch müsste man ja ein Objekt auch serialisieren können und dann in der NewAction daraus wieder ein Objekt erstellen können...
Hallo Stefan,
wie hast du es denn nun gelöst?
Gruß
alisha
hab jetzt nur kurz überflogen, aber eigentlich sollte das doch wunderbar mit forward statt redirect klappen.
$this->forward('new','Provider',null,array('provider' => $provider));
Hallo,
Warum sollte die Übergabe nicht bei redirect klappen?
Ansonsten haltet Euch an mein Beispiel im 2. Post. Im konkreten Beispiel für Dich Stefan: pack alle Formularelemente in ein Model, welches Du wie oben gezeigt übergibst. Im Tx_MyExt_Domain_Model_MyFormValidator kannst Du dann den Usernamen auch in der fe_users checken. Dies kannst Du machen indem Du ein neues Model/Repository anlegst und fe_users erweiterst oder Du fragst die Tabelle fe_users einfach hart codiert ab (wobei ich ausdrücklich betonen möchte, dass die erste Variante zu bevorzugen ist). Rein theoretisch kannst Du die Validierung auch in einem Tx_MyExt_Domain_Model_UserValidator, welches Du dann per Annotation im Formular-Model an den User bindest, durchführen.
Gibt es den User(namen) schon, kannst Du im Validator false zurückgeben und es wird - wie vom Framework vorgesehen - zur indexAction zurück-redirected und zwar mit Deinem Formular-Objekt inkl. aller Daten.
Es muss also niemand für solche Fälle ein redirect (und schon gar kein forward) mit Parametern benutzen, auch für dich alisha, wird es ohne mit Sicherheit auch ohne klappen. Falls Du Fragen hast, poste Deinen Code und wir optimieren das zusammen.
Beste Grüße, Sven
Hallo Sven,
du hast recht, ich habs auch ohne Parameter hinbekommen. Ich hab zwar kein Formular-Model gemacht, aber mit der newaction und createAction meines normalen Models hat es auch funktioniert. Ich weiß nicht, wo vorher das Problem lag...
Nun steh ich vor der letzten Hürde:
In meiner eigenen Validatorklasse möchte ich auf ein Formularwert zugreifen, der nicht zum Model gehört und auch nirgendwo gespeichert werden muss (Bestaetigung der Emailadresse), mit $this->request->getArgument erhalte ich eine Fehlermeldung, vermutlich weil request nur von einer Controller aufgerufen werden kann...
Muss ich jetzt doch noch so eine Formularmodel-Klasse machen oder gibt es noch eine einfachere Variante?
Mir fallen jetzt 3 Lösungen ein:
1. Formular-Model basteln, was die Bestätigung beinhaltet,
2. Model erweitern (also ne neue Klasse, die von Deiner Klasse ableitet) und als einziges Property die Bestätigung enthält
3. Versuchen, den POST-Parameter auszulesen
Dass ich 3. für unsauber halte muss ich bestimmt nicht sagen 😃
Wenn Du Dein Model nicht ändern kannst, bliebe die 2. Variante. Wenn die Daten dann mit der Oberklasse verarbeitet werden müssen, musst Du halt noch ein Mapping machen.
Ich selbst würde wohl 1. Variante umsetzen.
Hallo zusammen,
das ist jetzt ja doch noch ein richtiger Baum geworden...
Inzwischen ist mir einiges klarer, vor allem Sven hat es ja auf den Punkt gebracht.
Ich hätte natürlich die Fe_Users erweitern sollen, doch dafür ist es nun zu spät, oder ich muss später mal die Kundenverwaltung neu aufbauen.
Fürs Erste nehm ich jetzt tatsächlich die Werte, pack sie in ein Array und gebe das per redirect zurück.
Meine Sorge vor 'vergessenen' später zugefügten Feldern habe ich gelöst, ich übernehme die Daten einfach per
$neuesArray = $provider->_getProperties();
Dann muss ich nur mit unset($neuesArray['uid']) etc. die unbrauchbaren Teile löschen, aber das dürfte zuverlässiger sein als jedes Mal ein neues Feld zuzufügen.
Danke erstmal für Eure Ideen & Tipps!
Viele Grüße vom Rhein, Stefan
Hi,
und ich habe nun doch Model erweitert um das confirm-Feld, wenn es auch unnötig ist, dass es gespeichert wird - und in einer Validatorklasse überprüfe ich die Übereinstimmung der Felder. Die Validierung läuft jetzt komplett automatisch ab und die Werte der Felder werden jetzt auch bei Falschangabe / wiederholtem Aufruf automatisch übernommen...
also alles paletti :-)
Danke Sven!
viele Grüße
lizzy
jetzt hab ich leider doch noch ein unerklärliches Problem mit meinem Formular. Ich verwende ein- und diesselbe Technik bei mehreren Formularen und bei allen gehts nur bei einem ist das Objekt immer leer nach der validierung. Ich habe alle Caches und temporären Dateien gelöscht und ich finde es einfach komplett unlogisch, weil der Code nahezu identisch ist...
hier wird das Formular aufgerufen (abschließend in einer create-Action eines anderen Objekts)
$this->redirect('newPaarM', 'Application', Null, array('parameter'=>$parameter));
und hier die new-Action:
/* action newPaarM
* @param $newApplicationM
*
* @param Array $parameter
* @dontvalidate $newApplicationM
* @return void
*/
public function newPaarMAction(Tx_xx_Domain_Model_Application $newApplicationM = NULL, $parameter = NULL) {
if($newApplicationM == null){
$newApplicationM = t3lib_div::makeInstance('Tx_xx_Domain_Model_Application');
}
.. hier nutze ich noch die Parameter um andere Werte an das Formular zu binden, aber das hat ja nichts mit dem Problem zu tun...
$this->view->assign('newApplicationM', $newApplicationM);
}
und das formular:
<f:form method="post" action="createPaarM" name="newApplication" object="{newApplicationM}" >
wenn ich mir newApplicationM ausgeben lasse mit f:debug, dann sehe ich nur ein leeres Objekt... Ich verstehe es einfach nicht.. Wo ist nur das Problem?
vielleicht noch zum Verständnis:
Es geht darum, dass sich ein Paar anmeldet, zunächst wird das Formular für die Frau angezeigt, validiert, gespeichert und dann das für den Mann. Letzteres funktioniert nicht.
Ich habe das ganze auch noch in der Single - Variante, also Mann alleine und Frau alleine und da funktioniert auch alles...
Weiß jemand Rat?
Auf den ersten Blick sehe ich nur, dass beim Formularnamen ein 'M' hinten fehlt.
Wenn's daran nicht liegt, werfe ich nachher noch einen 2. Blick darauf.
Hallo Sven,
danke dass du nochmal drauf schaust.
Ich dachte nicht, dass der Formularname auch einen Bezug zum Objekt haben muss, aber du hast Recht, wenn ich den Namen in newApplicationM ändere werden die Eingaben übernommen. Nur hatte ich dann das Problem, dass die Fehlerbeschreibungen nicht mehr ausgegeben wurden, obwohl ich dort natürlich den Formularnamen auch geändert hatte. Aber nachdem ich in der dazugehörigen create-Methode auch den Variablennamen in newApplicationM geändert hatte funktioniert es nun. Mir ist nicht so ganz klar, warum der Name der Variable bzw. des Objekts funktionsübergreifend gleich sein muss, also warum muss sowohl in der new- als auch in der create-Methode der name gleich sein? Ich hätte erwartet, dass die create-Methode erkennt, dass ihr ein Objekt der xy-Klasse übergeben wird und gut ist...
Danke!
Hallo,
zur Gänze hab ich es mir auch nicht angeschaut was Extbase alles macht, aber meine Erkenntnisse:
Fluid erstellt das Formular anhand des Extension-, Plugin- und Formularnamens:
<f:form name="formName" object="{formName}">
<f:form.textbox property="firstName" />
...
wird zu
<form action="[..]/index.html">
<input type="text" name="tx_extensionname_pluginname[formName][firstName]" />
Deine create-, new-, index- oder wasAuchImmerAction in Extbase erkennt dann anhand des "tx_extensionname_pluginname", 'aha, das ist für mich'. Wenn Du im Parameter dann $formName angegeben hast, dann mappt er das auch auf das die Variable. Das heißt, dass Du (schätze ich) auch den Formnamen unterschiedlich zum Objektnamen benennen kannst, nur musst Du den Variablennamen in der Action anpassen. Ich benenn aber immer alles gleich, dann komm ich nicht durcheinander. In der Action gibst Du Deinem Parameter per Annotation noch Deine Formular-Klasse und schon hast Du auch ein Objekt. Klingt easy oder?