---
title: "Partielle Formular Validierung (multistep)"
url: "https://www.typo3.net/d/107647-partielle-formular-validierung-multistep"
source: "typo3.net"
tags: ["Extensions","Extbase","Frage"]
created: "2011-10-06"
last_reply: "2011-11-25"
replies: 1
solved: false
page: 1
pages: 1
lang: "de"
---

# Partielle Formular Validierung (multistep)

Extensions › Extbase · 1 Antwort · gestartet 2011-10-06

## Eröffnungsbeitrag

**Typo3Cuckoo** · 2011-10-06 · [Beitrag #1](https://www.typo3.net/d/107647-partielle-formular-validierung-multistep/1)

Hi,

ich bin gerade dabei ein mehrstufiges E-Mailformular zu erstellen, dessen Eingabefelder den Eigenschaften (Properties) eines Domain Models entsprechen.

Ich habe an folgende Anleitung gehalten:
<http://forge.typo3.org/projects/typo3v4-mvc/wiki/How_to_use_partial_validation_for_a_multi-step_form>
sowie
<http://lists.typo3.org/pipermail/typo3-project-typo3v4mvc/2011-May/009643.html>

Wenn ich das Formular in Schritt 2 mit leeren Eingabefeldern abschicke, dann erhalte ich FormErrors für alle Felder, also auch diejenigen, welche erst in Schritt 2 dran sind. Irgendwie greift diese partielle Valiedierung nicht :(

Hat das schon mal einer erfolgreich umgesetzt und könnte mir helfen?

Das Domain Model **MyDomainModel** sieht gekürzt so aus (hier stehen auch alle Validierungsregeln mittels Annotation @validate):

```php
<?php
class Tx_MyExt_Domain_Model_MyDomainModel extends Tx_Extbase_DomainObject_AbstractEntity {

	/**
	 * firstName
	 *
	 * @var string
	 * @validate notEmpty
	 */
	protected $firstName;

	/**
	 * __construct
	 * 
	 * @param array $data
	 */
	public function __construct() {
	}
	
	/**
	 * Returns the first name
	 *
	 * @return string $firstName
	 */
	public function getFirstName() {
		return $this->firstName;
	}
	
	/**
	 * Sets the first name
	 *
	 * @param string $firstName
	 * @return void
	 */
	public function setFirstName($firstName) {
		$this->firstName = $firstName;
	}
	
}
?>
```

Die **ExtendedValidatorResolver** Klasse (siehe Download ersten Link) liegt im Verzeichnis **ext_key/Classes/Valdation/ExtendedValidatorResolver.php** und sieht so aus:

```php
<?php
class Tx_MyExt_Validation_ExtendedValidatorResolver extends Tx_Extbase_Validation_ValidatorResolver {
	/**
	 * Builds a base validator conjunction for the given data type.
	 *
	 * The base validation rules are those which were declared directly in a class (typically
	 * a model) through some @validate annotations on properties.
	 * It will only validate the properties which are sent with the current request.
	 *
	 *
	 * @param string $dataType The data type to build the validation conjunction for. Needs to be the fully qualified object name.
	 * @return Tx_Extbase_Validation_Validator_ConjunctionValidator The validator conjunction or NULL
	 */
	public function buildBaseValidatorConjunctionWithRequestData($dataType, $rawRequest) {
		
		// Model based validator
		// This method looks almost exactly like "buildBaseValidatorConjunction" in ValidatorResolver.
		if (strstr($dataType, '_') !== FALSE && class_exists($dataType)) {
			$objectValidator = $this->createValidator('GenericObject');

			$validatorCount = 0;

			foreach ($this->reflectionService->getClassPropertyNames($dataType) as $classPropertyName) {
				$classPropertyTagsValues = $this->reflectionService->getPropertyTagsValues($dataType, $classPropertyName);
				if (!isset($classPropertyTagsValues['validate'])) continue;
				// This is the only real change to the ValidatorResolver: We only add the
				// validation for a property if this property has been changed in the current request.
				if (!is_array($rawRequest) || !isset($rawRequest[$classPropertyName])) continue;

				foreach ($classPropertyTagsValues['validate'] as $validateValue) {
					$parsedAnnotation = $this->parseValidatorAnnotation($validateValue);
					foreach ($parsedAnnotation['validators'] as $validatorConfiguration) {
						$newValidator = $this->createValidator($validatorConfiguration['validatorName'], $validatorConfiguration['validatorOptions']);
						if ($newValidator === NULL) {
							throw new Tx_Extbase_Validation_Exception_NoSuchValidator('Invalid validate annotation in ' . $dataType . '::' . $classPropertyName . ': Could not resolve class name for  validator "' . $validatorConfiguration['validatorName'] . '".', 1241098027);
						}
						$objectValidator->addPropertyValidator($classPropertyName, $newValidator);
						$validatorCount ++;
					}
				}
			}
			if ($validatorCount > 0) return $objectValidator;
		}
		return $this->createValidator('Conjunction'); // Just a validator returning TRUE; in case no validation needs to take place.
		
	}
}
?>
```

Davon abgeleitet die **Subclass** (siehe ersten Link), welche dann vom eigentlichen Controller geerbt wird:

```php
<?php
class Tx_MyExt_Controller_MultiStepFormController extends Tx_Extbase_MVC_Controller_ActionController {

	/**
	 * If you need a multi-step form which updates a domain object, you only want properties validated which are
	 * sent with the current request. This method should be called in the corresponding initialize*Action,
	 * and it will rebuild the registered validators for this argument.
	 *
	 * It will also respect the @validate annotation on the action method name.
	 *
	 * THIS METHOD WILL NOT CHECK A @dontvalidate ANNOTATION. Thus, it should NOT be used
	 * for displaying a form, but instead be used for SAVING data.
	 *
	 * @param string $argumentName The name of the argument where the partial validator should be registered for.
	 */
	protected function registerPartialValidatorForArgument($argumentName) {
		
		if ($this->request->hasArgument($argumentName)) {
			
			// Initialize the extended validator resolver.
			$extendedValidatorResolver = t3lib_div::makeInstance('Tx_MyExt_Validation_ExtendedValidatorResolver');
			$extendedValidatorResolver->injectObjectManager(t3lib_div::makeInstance('Tx_Extbase_Object_Manager')); // Singleton
			$extendedValidatorResolver->injectReflectionService(t3lib_div::makeInstance('Tx_Extbase_Reflection_Service')); // Singleton
			
			// Load all parameter validators and pick the one for the current argument, as this is the base validator.
			$parameterValidators = $this->validatorResolver->buildMethodArgumentsValidatorConjunctions(get_class($this), $this->actionMethodName);
			$baseValidator = $parameterValidators[$argumentName];
			
			// Build up the validator for all submitted data.
			$rawRequestDataForArgument = $this->request->getArgument($argumentName);
			$argument = $this->arguments[$argumentName];
			$partialValidator = $extendedValidatorResolver->buildBaseValidatorConjunctionWithRequestData($argument->getDataType(), $rawRequestDataForArgument);
			
			// Add the partial validator to the base validator; and override the validations of the argument.
			$baseValidator->addValidator($partialValidator);
			$argument->setValidator($baseValidator);
		}
	}
	
}
?>
```

Und hier der Crontoller zum Domain Model **MyDomainModel** von oben:

```php
<?php
class Tx_MyExt_Controller_MyDomainModelController extends Tx_MyExt_Controller_MultiStepFormController {

	/**
	 * Show Step 1
	 * 
	 * @param Tx_MyExt_Domain_Model_MyDomainModel $myDomainModel
	 * @dontvalidate $myDomainModel
	 * 
	 * @return string A HTML Form
	 */
	public function showStep1Action(Tx_MyExt_Domain_Model_MyDomainModel $myDomainModel=NULL) {
		$this->view->assign('myDomainModel', $myDomainModel);
	}
	
	/**
	 * Save Step 1
	 * 
	 * @param Tx_MyExt_Domain_Model_MyDomainModel $myDomainModel
	 * 
	 * @return string A HTML Form
	 */
	public function saveStep1Action(Tx_MyExt_Domain_Model_MyDomainModel $myDomainModel) {
		$this->redirect('showStep2');
	}
	
	/**
	 * Initialize Save Step 1
	 * 
	 * @return void
	 */
	public function initializeSaveStep1Action() {
		$this->registerPartialValidatorForArgument('firstName');
		$this->registerPartialValidatorForArgument('lastName');
		$this->registerPartialValidatorForArgument('birthdayDay');
		$this->registerPartialValidatorForArgument('birthdayMonth');
		$this->registerPartialValidatorForArgument('birthdayYear');
		$this->registerPartialValidatorForArgument('company');
		$this->registerPartialValidatorForArgument('street');
		$this->registerPartialValidatorForArgument('postalCode');
		$this->registerPartialValidatorForArgument('city');
		$this->registerPartialValidatorForArgument('email');
	}
	
	/**
	 * Show Step 2
	 * 
	 * @param Tx_MyExt_Domain_Model_MyDomainModel $myDomainModel
	 * @dontvalidate $myDomainModel
	 * 
	 * @return string A HTML Form
	 */
	public function showStep2Action(Tx_MyExt_Domain_Model_MyDomainModel $myDomainModel) {
		$this->view->assign('myDomainModel', $myDomainModel);
	}

	/**
	 * Save Step 2
	 * 
	 * @param Tx_MyExt_Domain_Model_MyDomainModel $myDomainModel
	 * 
	 * @return string A HTML Form
	 */
	public function saveStep2Action(Tx_MyExt_Domain_Model_MyDomainModel $myDomainModel) {
		$this->redirect('submit');
	}
	
	/**
	 * Initialize Save Step 2
	 * 
	 * @return void
	 */
	public function initializeSaveStep2Action() {
		$this->registerPartialValidatorForArgument('agb');
	}

	/**
	 * Show Submit View
	 * 
	 * @param Tx_MyExt_Domain_Model_MyDomainModel $myDomainModel
	 * @dontvalidate $myDomainModel
	 * 
	 * @return string A HTML Form
	 */
	public function submitAction(Tx_MyExt_Domain_Model_MyDomainModel $myDomainModel) {
		$this->view->assign('myDomainModel', $myDomainModel);
	}
}
?>
```

Schaut man sich die **initializeSaveStep*Action** Methoden an, dann sieht man, dass das Feld **agb** erst in Schritt 2 validiert werden soll, wie jedoch oben beschrieben erhalte ich schon in Schritt 1 die Validierungsfehlermeldungen für alle im Domain Model mit der Annotation @validate versehenen Eigenschaften:

```php
firstName: The given subject was empty.
lastName: The given subject was empty.
birthdayDay: The given subject was empty.
birthdayMonth: The given subject was empty.
birthdayYear: The given subject was empty.
company: The given subject was empty.
street: The given subject was empty.
postalCode: The given subject was empty.
city: The given subject was empty.
email: The given subject was empty.
agb: The given subject was NULL.  <--- Das dürfte erst in Schritt 2 validiert werden!
```

Die Fluid Templates erspar ich euch jetzt mal (falls ihr sie braucht/wollt werd ich die nachreichen).

Ich hoffe ihr könnt mir weiterhelfen :)

## Antworten

### [#2](https://www.typo3.net/d/107647-partielle-formular-validierung-multistep/2) · vizArt · 2011-11-25

Hi Typo3Cuckoo,

da ich das gleiche Problem hatte, und irgendwann meinen "Denkfehler" gefunden hatte, hab ich ein kleines Beispiel-Plugin geschrieben. Dieses habe ich dem Artikel <http://forge.typo3.org/projects/typo3v4-mvc/wiki/How_to_use_partial_validation_for_a_multi-step_form> ergänzt.

Prinzipiell liegt aber unser Fehler darin, dass wir dachten es müsse die Property in die registerPartialValidatorForArgument() - Methode übergeben werden.
Dies ist jedoch falsch. Du übergibst sozusagen das "model-object".

In Deinem Besipiel wäre das:

```php
<?php
/**
 * Initialize Save Step 1
 * 
 * @return void
 */
 public function initializeSaveStep1Action() {
    $this->registerPartialValidatorForArgument($myDomainModel);
  }
?>
```

Die Technik von Sebastian erkennt selbst welche Properties übergeben wurden, und wendet darauf dann die validierung an.

Ich hoffe ich konnte Dir helfen
LG viz

---

Quelle: „Partielle Formular Validierung (multistep)“, typo3.net, https://www.typo3.net/d/107647-partielle-formular-validierung-multistep
Beiträge von Mitgliedern des Forums. Bitte mit Link auf die Diskussion zitieren.
