Formulare mit Extbase und Fluid: Unterschied zwischen den Versionen
| (19 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 3: | Zeile 3: | ||
== Überblick == | == Überblick == | ||
| + | * Falls nicht vorhanden gewünschte Action registrieren (localconf) und im Controller anlegen | ||
* Fluid Form erstellen | * Fluid Form erstellen | ||
| + | * Mit Absenden oder AJAC Call ausführen | ||
=== Formular Felder im Fluid Template === | === Formular Felder im Fluid Template === | ||
| − | ==== Form Tag ==== | + | 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''' | ||
<pre> | <pre> | ||
<f:form action="BestimmteFormAction" controller="BestimmterControllerName" extension="AndererExtensionName" enctype="multipart/form-data"> | <f:form action="BestimmteFormAction" controller="BestimmterControllerName" extension="AndererExtensionName" enctype="multipart/form-data"> | ||
| Zeile 11: | Zeile 27: | ||
</f:form> | </f:form> | ||
</pre> | </pre> | ||
| − | Beispiel | + | '''Beispiel''' |
<pre> | <pre> | ||
<f:form action="create" object="{newProject}"> | <f:form action="create" object="{newProject}"> | ||
| Zeile 18: | Zeile 34: | ||
</f:form> | </f:form> | ||
</pre> | </pre> | ||
| − | Das Controller Attribut benötigt man nur dann, wenn der Controller der die Daten auswerten soll nicht zum aktuellen View gehört. | + | Das '''Controller Attribut''' benötigt man '''nur dann, wenn der Controller der die Daten auswerten soll nicht zum aktuellen View gehört.''' |
| + | |||
==== Name Attribute ==== | ==== Name Attribute ==== | ||
Das '''name-Attribut''' wird automatisch für das Plugin passend umgewandelt. | Das '''name-Attribut''' wird automatisch für das Plugin passend umgewandelt. | ||
| Zeile 32: | Zeile 49: | ||
</pre> | </pre> | ||
Extbase vergleicht dabei zusätzlich automatisch die Felder aus dem Formular mit dem Model '''validiert automatisch'''. | Extbase vergleicht dabei zusätzlich automatisch die Felder aus dem Formular mit dem Model '''validiert automatisch'''. | ||
| + | |||
| + | ==== Upload Feld ==== | ||
| + | <f:form.upload name="myExtName[image]" /> | ||
| + | <f:form.upload property="file" /> | ||
| + | <f:form.upload property="image" /> | ||
| + | |||
| + | == 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: | ||
| + | <syntaxhighlight lang="html5"> | ||
| + | <f:for each="{dinge}" as="ding"> | ||
| + | <f:link.action action="show" arguments="{ding : ding}">Los</f:link.action> | ||
| + | </f:for> | ||
| + | </syntaxhighlight> | ||
| + | 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 | ||
| + | <syntaxhighlight lang="php"> | ||
| + | public function showAction(\TYPO3\Extension\Domain\Model\Dinge $dinge, $key) | ||
| + | </syntaxhighlight> | ||
| + | oder im Controller selbst | ||
| + | <syntaxhighlight lang="php"> | ||
| + | $key = $this->request->getArgument('key'); | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | === Dynamisch validieren je nach Auswahl === | ||
| + | http://blog.teamgeist-medien.de/2015/05/typo3-extbase-dynamische-validierung-von-models-je-nach-formularauswahl.html | ||
| + | === 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: | ||
| + | |||
| + | <pre> | ||
| + | <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> | ||
| + | </pre> | ||
| + | |||
| + | === 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: | ||
| + | <pre> | ||
| + | /** | ||
| + | * CAPTCHA | ||
| + | * | ||
| + | * @var string | ||
| + | * @validate NotEmpty, Tx_MyExt_Validation_Validator_CaptchaValidator | ||
| + | */ | ||
| + | protected $captcha; | ||
| + | </pre> | ||
| + | Möglichkeit 2 - Validierer im Controller initialisieren | ||
| + | |||
| + | http://blog.sebastiaandejonge.com/articles/2013/january/17/form-validation-of-non-domain-model-properties-with-extbase/ | ||
| + | |||
| + | === Statische Optionen in Selectboxen === | ||
| + | http://docs.typo3.org/typo3cms/ExtbaseGuide/stable/Fluid/BestPractice/OptionsForSelect.html | ||
| + | |||
| + | === Hinzufügen von Child Objekten (1:n Verbindung) === | ||
| + | Quelle: http://snippets.in2code.de/index.php?id=273&tx_in2snippets_pi1%5Bsnippet%5D=74&tx_in2snippets_pi1%5Baction%5D=detail&tx_in2snippets_pi1%5Bcontroller%5D=Snippet&cHash=20bf6bed1ab88b5bd571fa8cc5aefd6b | ||
| + | |||
| + | '''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 : | ||
| + | |||
| + | <syntaxhighlight lang="php"> | ||
| + | protected function initializeUpdateAction() { | ||
| + | $mvcPropertyMappingConfiguration = \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationBuilder::build( | ||
| + | 'TYPO3\\CMS\\Extbase\\Mvc\\Controller\\MvcPropertyMappingConfiguration' | ||
| + | ); | ||
| + | $this->arguments->getArgument('mother')->injectPropertyMappingConfiguration($mvcPropertyMappingConfiguration); | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | |||
| + | 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! | ||
Aktuelle Version vom 22. Oktober 2015, 06:22 Uhr
Links[Bearbeiten]
http://docs.typo3.org/typo3cms/ExtbaseGuide/Fluid/ViewHelper/Form/Index.html
Überblick[Bearbeiten]
- 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[Bearbeiten]
http://wiki.typo3.org/Fluid#f:form http://wiki.typo3.org/Fluid#form_fields
Input Feld[Bearbeiten]
<f:form.textfield property="rmaType" />
Textarea[Bearbeiten]
<f:form.textarea name="myExtName[nachricht]" />
oder
<f:form.textarea property="nachricht" />
Radio Buttons[Bearbeiten]
http://wiki.typo3.org/Fluid#f:form.radio http://docs.typo3.org/typo3cms/ExtbaseGuide/Fluid/ViewHelper/Form/Radio.html
Form Tag (Action)[Bearbeiten]
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[Bearbeiten]
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.
Upload Feld[Bearbeiten]
<f:form.upload name="myExtName[image]" /> <f:form.upload property="file" /> <f:form.upload property="image" />
Tipps und Tricks[Bearbeiten]
Zusätzliche Argumente im <f:link.action> View Helper[Bearbeiten]
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[Bearbeiten]
Typo3/Fluid: Verschiedene Models über ein Formular bedienen[Bearbeiten]
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[Bearbeiten]
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[Bearbeiten]
http://docs.typo3.org/typo3cms/ExtbaseGuide/stable/Fluid/BestPractice/OptionsForSelect.html
Hinzufügen von Child Objekten (1:n Verbindung)[Bearbeiten]
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!