2010-07-26 5 views
2

J'ai un formulaire symfony 1.4 avec 2 formes incorporées.Comment valider/enregistrer un formulaire incorporé basé sur une valeur dans le formulaire parent dans symfony?

Le formulaire parent possède un menu déroulant qui détermine lequel des formulaires incorporés que vous remplissez (masqué/affiché sur le frontend en utilisant JavaScript). Le problème est que lorsque je soumets le formulaire, la validation et l'enregistrement sont exécutés sur les deux formulaires incorporés, ce que je ne souhaite évidemment pas. Quel est le meilleur moyen de modifier le formulaire parent afin qu'il ne valide et n'enregistre le formulaire incorporé pertinent en fonction de la sélection faite dans le formulaire parent?

Merci.

Répondre

1

Note: S'il vous plaît voir la réponse de jeremy que la mienne est basée sur le sien.

Merci pour votre réponse jeremy. Votre code comportait quelques problèmes et j'ai donc décidé de poster ma solution implémentée en expliquant ce que je faisais différemment.

1. Remplacer doBind()

La substitution de doBind() a eu un problème où une sfValidatorError uncaught serait levée si la valeur mère ne revenait pas propre du validateur. Je l'ai enveloppé dans un essai/attraper pour supprimer ceci. Je l'ai également modifié pour travailler avec plusieurs formes incorporées, pas seulement les deux que j'ai spécifiées.

protected $selectedTemplate; 

public function getTemplateToEmbeddedFormKeyMap() 
{ 
    // An array of template values to embedded forms 
    return array(
     'template1' => 'templateform1', 
     'template2' => 'templateform2', 
     'template3' => 'templateform3', 
     'templateN' => 'templateformN' 
    ); 
} 

protected function doBind(array $values) 
{ 
    // Clean the "template" value 
    try 
    { 
     $this->selectedTemplate = $this->validatorSchema['template']->clean(array_key_exists('template', $values) ? $values['template'] : NULL); 
    } 
    catch(sfValidatorError $e) {} 

    // For each template embedded form 
    foreach($this->getTemplateToEmbeddedFormKeyMap() as $template => $form_key) 
    { 
     // If there is no selected template or the embedded form is not for the selected template 
     if ($this->selectedTemplate == NULL || $this->selectedTemplate != $template) 
     { 
      // Don't validate it 
      $this->validatorSchema[$form_key] = new sfValidatorPass(); 
     } 
    } 

    // Parent 
    parent::doBind($values); 
} 

2. NOUVEAU PAS Remplacer updateObjectEmbeddedForms()

Parce que j'ai validation désactivé sur une partie ou l'ensemble de mes formes embarquées, nous avons maintenant des données non nettoyés dans le tableau de valeurs de $. Je ne souhaite pas que ces données soient transmises à mes objets de modèle dans les formulaires incorporés. J'ai donc remplacé updateObjectEmbeddedForms() pour supprimer toutes les données relatives à un formulaire incorporé qui n'est pas validé.

public function updateObjectEmbeddedForms($values, $forms = null) 
{ 
    // For each template embedded form 
    foreach($this->getTemplateToEmbeddedFormKeyMap() as $template => $form_key) 
    { 
     // If there is no selected template or the embedded form is not for the selected template 
     if ($this->selectedTemplate == NULL || $this->selectedTemplate != $template) 
     { 
      // Remove the data 
      unset($values[$form_key]); 
     } 
    } 

    // Parent 
    parent::updateObjectEmbeddedForms($values, $forms); 
} 

3. Remplacer saveEmbeddedForms()

Et enfin, je ne suis pas que je devais copier et coller l'ensemble de la méthode de base saveEmbeddedForms() puis le modifier, donc je refactorisé pour enlever la Je ne veux pas sauvegarder les formes incorporées avant de les transmettre au parent.

public function saveEmbeddedForms($con = null, $forms = null) 
{ 
    // Get the embedded forms 
    if ($forms === NULL) 
    { 
     $forms = $this->getEmbeddedForms(); 
    } 

    // For each template embedded form 
    foreach($this->getTemplateToEmbeddedFormKeyMap() as $template => $form_key) 
    { 
     // If there is no selected template or the embedded form is not for the selected template 
     if ($this->selectedTemplate == NULL || $this->selectedTemplate != $template) 
     { 
      // Remove the form so it isn't saved 
      unset($forms[$form_key]); 
     } 
    } 

    // Parent 
    parent::saveEmbeddedForms($con, $forms); 
} 

Merci encore pour la réponse jeremy, cela m'a permis d'obtenir ce qui fonctionne pour mon cas d'utilisation.

0

Vous trouverez ci-dessous une manière généralisée de procéder. Toutes ces méthodes peuvent être ajoutées à BaseFormDoctrine excepté doBind

1. Ajoutez une méthode pour ignorer les formulaires.

/** 
* @param string $name Adds $name to an array of form names to ignore when saving/updating. 
*/ 
protected function skipSavingForm($name) 
{ 
    $this->skipSavingForms[$name] = $name; 
    $this->validatorSchema[$name] = new sfValidatorPass(); 
} 

2. Remplacer doBind de telle sorte que la forme que vous ne sauvegardez pas n'est pas validée

De cette façon, même si la forme qui ne sont pas en cours d'enregistrement est soumis à des erreurs, la forme encore valide C'est sûr car ces valeurs ne sont pas sauvegardées. Vous pouvez également effacer les valeurs avec un preValidator. Cependant, je préfère cette solution de sorte que si l'utilisateur soumet le formulaire avec une erreur, ses valeurs pour les deux formes sont toujours là.

/** 
* Override doBind to skip validation on the form not being saved 
* @param array $values 
* @see sfForm::doBind 
*/ 
protected function doBind(array $values) 
{ 
    try 
    { 
    $formDecidingValue = $this->validatorSchema[$values['form_deciding_field']]->clean(); 
    } catch (sfValidatorError $e) { 
    //either create an sfValidatorErrorSchema and throw it or call through to parent here and let parent::doBind throw the error 
    return; //either way, we want to stop processing 
    } 

    $this->skipSavingForm($formDecidingValue ? 'Form1' : 'Form2'); 
    return parent::doBind($values); 
} 

3. Ajouter une méthode getFormsToSave

/** 
*@return array An array of forms to be saved 
*/ 
public function getFormsToSave() 
{ 
    return array_diff_key($this->getEmbeddedForms(), $this->skipSavingForms); 
} 

4. Remplacer saveEmbeddedForms et updateObjectEmbeddedForms

Alors que la forme sautée est pas enregistré. Alternativement, si vous n'avez pas besoin de continuer à afficher le formulaire sur une erreur, vous pouvez simplement annuler l'embeddedForm dans doBind.

public function saveEmbeddedForms($con = null, $forms = null) 
{ 
    if (null === $con) 
    { 
    $con = $this->getConnection(); 
    } 

    if (null === $forms) 
    { 
    $forms = $this->getFormsToSave(); 
    } 

    foreach ($forms as $form) 
    { 
    if ($form instanceof sfFormObject) 
    { 
     $form->saveEmbeddedForms($con); 
     $form->getObject()->save($con); 
    } 
    else 
    { 
     $this->saveEmbeddedForms($con, $form->getFormsToSave()); 
    } 
    } 
} 

public function updateObjectEmbeddedForms($values, $forms = null) 
{ 
    if (null === $forms) 
    { 
    $forms = $this->getFormsToSave(); 
    } 

    foreach ($forms as $name => $form) 
    { 
    if (!isset($values[$name]) || !is_array($values[$name])) 
    { 
     continue; 
    } 

    if ($form instanceof sfFormObject) 
    { 
     $form->updateObject($values[$name]); 
    } 
    else 
    { 
     $this->updateObjectEmbeddedForms($values[$name], $form->getFormsToSave()); 
    } 
    } 
} 
+0

Merci pour votre réponse. J'ai trouvé quelques problèmes et je l'ai prolongé un peu, mais c'était une base solide pour ce que je voulais faire. J'ai posté ma solution si vous voulez faire un commentaire. Bravo encore! –

+0

J'ai nettoyé mon. Vous avez raison de vouloir ignorer updateObjectEmbeddedForms. –

Questions connexes