Formulare mit Extbase und Fluid: Unterschied zwischen den Versionen
| Zeile 11: | Zeile 11: | ||
==== Input Feld ==== | ==== Input Feld ==== | ||
<f:form.textfield property="rmaType" /> | <f:form.textfield property="rmaType" /> | ||
| + | ==== Textarea ==== | ||
| + | <f:form.textarea name="myExtName[nachricht]" /> | ||
| + | oder | ||
| + | <f:form.textarea property="nachricht" /> | ||
| + | |||
==== Radio Buttons ==== | ==== Radio Buttons ==== | ||
http://wiki.typo3.org/Fluid#f:form.radio | http://wiki.typo3.org/Fluid#f:form.radio | ||
Version vom 8. Oktober 2015, 12:12 Uhr
Links
http://docs.typo3.org/typo3cms/ExtbaseGuide/Fluid/ViewHelper/Form/Index.html
Überblick
- Falls nicht vorhanden gewünschte Action registrieren (localconf) und im Controller anlegen
- Fluid Form erstellen
- Mit Absenden oder AJAC Call ausführen
Formular Felder im Fluid Template
http://wiki.typo3.org/Fluid#f:form http://wiki.typo3.org/Fluid#form_fields
Input Feld
<f:form.textfield property="rmaType" />
Textarea
<f:form.textarea name="myExtName[nachricht]" />
oder
<f:form.textarea property="nachricht" />
Radio Buttons
http://wiki.typo3.org/Fluid#f:form.radio http://docs.typo3.org/typo3cms/ExtbaseGuide/Fluid/ViewHelper/Form/Radio.html
Form Tag (Action)
Beispiel
<f:form action="BestimmteFormAction" controller="BestimmterControllerName" extension="AndererExtensionName" enctype="multipart/form-data"> Form-Felder </f:form>
Beispiel
<f:form action="create" object="{newProject}">
Projektname: <f:form.textbox property="name" />
<f:form.submit value="Speichern" />
</f:form>
Das Controller Attribut benötigt man nur dann, wenn der Controller der die Daten auswerten soll nicht zum aktuellen View gehört.
Name Attribute
Das name-Attribut wird automatisch für das Plugin passend umgewandelt.
<f:form.textfield name="myField" />
wird zu
<input type="text" name="tx_registierung_pi1[myField]" />
Sendet das Formular nun z.B. an einen Controller: showAction, stehen die Werte als Argumente zur Verfügung:
public function showAction() {
$args = $this->request->getArguments();
echo $args['myField];
}
Extbase vergleicht dabei zusätzlich automatisch die Felder aus dem Formular mit dem Model validiert automatisch.
Tipps und Tricks
Zusätzliche Argumente im <f:link.action> View Helper
Standardmäßig sieht ein Action Link z.B. in der Listenansicht etwa so aus:
<f:for each="{dinge}" as="ding">
<f:link.action action="show" arguments="{ding : ding}">Los</f:link.action>
</f:for>
Es wird also ein ding-Objekt mit dem Bezeichner "ding" übergeben. Möchte man weitere Argumente außer dem Objekt absetzen, z.B. ein String geht das so:
arguments="{ding : ding, key : 'wert'}"
Es wird zusätzlich eine Variable key mit dem Wert 'wert' übergeben.
Im Controller holt man sich den Wert wieder raus:
Als Argument in der Controller Deklarierung
public function showAction(\TYPO3\Extension\Domain\Model\Dinge $dinge, $key)
oder im Controller selbst
$key = $this->request->getArgument('key');
Dynamisch validieren je nach Auswahl
Typo3/Fluid: Verschiedene Models über ein Formular bedienen
Quelle: http://www.muenster-webdesign.net/blog/typo3fluid-verschiedene-models-ueber-ein-formular-bedienen/ (2015-03)
Dank der form-ViewHelper lassen sich Formulare mittels Extbase/Fluid recht zügig umsetzen. Bei komplexeren Szenarien, bei denen in einem Formular mehrere verschiedene Models bedient werden sollen, stellt sich jedoch die Frage, wie sich dies umsetzen lässt.
Die Lösung liegt darin, mit “namebased input”-Felder zu arbeiten. Statt also wie üblich eine Eigenschaft im Fluid-Formular per “property”-Attribut an ein Objekt zu binden, definiert man stattdessen die Argumente “name” und “value” manuell.
Ein Beispiel. Ein Formular ist per “object”-Attribut an ein Objekt “schornsteinfeger” gebunden. Soll im Formular nun gleichzeitig eine Eigenschaft “aussentemperatur” eines Objekts “wetter” bedient werden, könnte das Ganze etwa so aussehen:
<f:form method="post" action="create" name="schornsteinfeger" enctype="multipart/form-data" object="{schornsteinfeger}">
<f:form.textbox name="wetter[aussentemperatur]" value={wetter.aussentemperatur} />
</f:form>
Felder validieren die nicht im Domain-Model vorhanden sind
Wenn man z.B. ein Captcha einbauen möchte braucht man Felder die nicht im Model sind. Die eingebauten Sicherheitsmechanismen in Extbase lassen dass aber nicht ohne weiteres zu. Hier wird ja automatisch jeder Wert mit dem Model abgeglichen. Möglichkeit 1 - Dummy Felder in das Model einbauen:
/** * CAPTCHA * * @var string * @validate NotEmpty, Tx_MyExt_Validation_Validator_CaptchaValidator */ protected $captcha;
Möglichkeit 2 - Validierer im Controller initialisieren
Statische Optionen in Selectboxen
http://docs.typo3.org/typo3cms/ExtbaseGuide/stable/Fluid/BestPractice/OptionsForSelect.html
Hinzufügen von Child Objekten (1:n Verbindung)
Snippet zum Speichern von 1:n relations in dynamisch erzeugten Formularen.
Erklärung unter Verwendung der folgenden Problemstellung:
Es sind die folgenden Objekte vorhanden:
1. Mutter
2. Kind
Eine Mutter hat mehrere Kinder, diese werden in Extbase in einer Object Storage gespeichert. Wenn man ein neues Kind hinzufügen will, wäre der Standardweg die newAction im ChildController aufzurufen.
Da man aber das Kind in dem Formular der Mutter 'erzeugen' will, muss man entweder dem Formular ein neues Kind von Haus aus mitgeben (hiervon wird dringend abgeraten!) oder die Formularfelder für das Kind dynamisch erzeugen (javascript ftw).
Fluid kennt das Objekt ObjectStorage und kann über den path syntax auch damit umgehen
<f:form.textfield property="mother.children.0.firstName" />
-> der Vorname des ersten Kindes der Mutter.
Schickt man das Formular so ab, bekommt man jedoch die Fehlermeldung, dass man
a) properties nicht mappen darf und/oder
b) dass das erzeugen neuer Objekte nicht erlaubt ist.
Der Core stellt dazu Methoden bereit, die jedoch in keiner/keinem Docu/Manual auftauchen.
Als Erstes benötigt man eine initialize<method>Action, in diesem Fall:
protected function initializeUpdateAction() { ... }
diese wird vor der eigentlichen Methode aufgerufen (updateAction) (Convention!). Das ermöglich einem die PropertyMappingConfiguration anzupassen.
Die PropertyMappingConfiguration ist erstmal leer. Also baut man sich eine neue, die dann direkt injected wird :
protected function initializeUpdateAction() {
$mvcPropertyMappingConfiguration = \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationBuilder::build(
'TYPO3\\CMS\\Extbase\\Mvc\\Controller\\MvcPropertyMappingConfiguration'
);
$this->arguments->getArgument('mother')->injectPropertyMappingConfiguration($mvcPropertyMappingConfiguration);
}
Jetzt müssen die property-mapping-Einstellungen gemacht werden. Extbase ist so aufgebaut, dass man Objekte nur über von Fluid erstellte Formulare ändern kann (trustedPropertiesToken). Dies verhindert genau das, was man hier erreichen möchte. Ein Objekt mit dynamisch erzeugten Formularfeldern verändern oder erzeugen. Geblockt ist die Funktion übrigens aus Sicherheitsgründen.
Um das hinzufügen und erstellen neuer Objekte zuzulassen, gibt es mehrere Methoden in der PropertyMappingConfiguration:
1) allowAllProperties() 2) allowAllPropertiesExcept(<string>) 3) allowProperties(<csv-string>) 4) allowCreationForSubProperty(<string>) 5) allowModificationForSubProperty(<string>)
Das tollste Feature dieser Methoden ist wohl, dass sie den Fluid path-syntax UND wildcards ('*') unterstützen. Desweiteren bietet die Methode forProperty() den Zugriff auf tiefere Eigenschaften. Um also Kinder der Mutter hinzufügen zu dürfen, muss man das Extbase mit
$propertyMappingConfiguration->forProperty('children')->allowAllProperties();$propertyMappingConfiguration->forProperty('children')->allowCreationForSubProperty('*');
klar machen.
allowAllProperties() gewährt einem dabei grundlegenden Zugriff auf die Eigenschaft children des Objekts und allowCreationForSubProperty('*') ermöglicht es, beliebig viele Kinder anzulegen. Das Wildcard ersetzt hierbei die Zahl im Fluid path-syntax.
Damit man den Kindern noch Vornamen und Geburtstag (uv.m.) geben kann, muss man diese Eigenschaften noch 'freischalten':
$propertyMappingConfiguration->forProperty('children')->forProperty('*')->allowAllProperties();
Natürlich kann man auch den Zugriff auf bestimmte Eigenschaften beschränken:
$propertyMappingConfiguration->forProperty('children')->forProperty('*')->allowProperties('firstname','birthday','birthplace','custody');
Nun gilt es noch zu beachten:
Wenn die ObjectStorage einmal befüllt ist und ein neues Objekt hinzugefügt werden soll, müssen alle bisherigen Objekte erneut mitgegeben werden, sonst wird die Verbindung zu den alten Objekten gelöscht!