2011-11-17 17 views
13

Attualmente sto sviluppando un sito Web in cui l'utente può acquistare buoni regalo. Sto usando un modulo in tre fasi utilizzando il pacchetto CraueFormFlow e tutto ciò riguarda i passaggi. Sono in grado di convalidare ogni semplice Assert (come non vuoto, email, campi ripetuti, ecc.) Ma sto affrontando la situazione in cui, l'utente può selezionare 0 carte regalo e procedere alla pagina successiva.Convalida del modulo Symfony2 basata su due campi

Gli utenti possono scegliere la quantità di gift card che desiderano acquistare utilizzando due distinti: uno per 25 carte regalo $ e uno per 50 carte regalo $. Quindi non posso semplicemente mettere un validatore che dice "il valore 0 non è permesso". Il validatore deve impedire a un utente di lasciare la quantità "0" in entrambi gli importi (25 $ e 50 $).

Qualcuno sa come effettuare una convalida personalizzata cercando i valori in due campi?

Grazie in anticipo!

risposta

30

Avete molte soluzioni per questo.

Il più semplice è aggiungere un Callback constraint alla classe del modello.

Un altro modo per farlo sarebbe creare il vincolo personalizzato e il relativo validatore associato. Hai un cookbook explaining how to create a custom validation constrain. Questo è l'approccio migliore per farlo.

Come il vostro vincolo non si applica a una proprietà, ma a una classe, è necessario specificare che l'override del metodo ->getTargets() della classe vincolo:

class MyConstraint extends Constraint 
{ 
    // ... 

    public function getTargets() 
    { 
     return Constraint::CLASS_CONSTRAINT; 
    } 
} 

Quindi il valore passato come $value argomento del metodo ->isValid() conterrà i valori dell'intera classe e non solo di una singola proprietà.

+3

Potrebbe spiegarmi come implementare il vincolo di callback? Sto guardando il documento Symfony2 e non so come accedere ai valori che voglio controllare nella funzione [...] isValid(). –

+0

Sembra che non funzioni quando non esiste una classe dati (quando si lavora con gli array). – umpirsky

3

Usa espressioni regolari inorder per evitare Zero

Nella classe Entity annotare la funzione di override di seguito, e di specificare la vostra proprietà che è necessario per la convalida.

L'esempio seguente è per la convalida di un codice PIN, qui nel campo del codice PIN ammetto solo numeri 0-9 combinazioni fino a 10 cifre.

"^ \ d + $" questa è l'espressione regolare che ho usato per prevenire altri caratteri.

Per l'override questa funzione è necessario includere le classi inferiori

use Symfony\Component\Validator\Mapping\ClassMetadata;// for overriding function loadValidatorMetadata() 

use Symfony\Component\Validator\Constraints\NotBlank;// for notblank constrain 

use Symfony\Component\Validator\Constraints\Email;//for email constrain 

use Symfony\Component\Validator\Constraints\MinLength;// for minimum length 

use Symfony\Component\Validator\Constraints\MaxLength; // for maximum length 

use Symfony\Component\Validator\Constraints\Choice; // for choice fields 

use Symfony\Component\Validator\Constraints\Regex; // for regular expression 



public static function loadValidatorMetadata(ClassMetadata $metadata) 
    { 
     $metadata->addPropertyConstraint('pincode', new NotBlank(array('message' => 'Does not blank'))); 
     $metadata->addPropertyConstraint('pincode', new Regex(array('pattern'=>'/^\d+$/','message' => 'must be number'))); 
     $metadata->addPropertyConstraint('pincode', new MaxLength(array('limit'=>'6','message' => 'must maximum 6 digits'))); 
     $metadata->addPropertyConstraint('pincode', new MinLength(array('limit'=>'6','message' => 'must minimum 6 digits'))); 


    } 

Non dimenticare tutti questi must

compresi nella classe Entity

che è necessario convalidare. Quindi nel tuo caso usa un'espressione regolare appropriata che non permetta '0'.

Felice di codifica

12

quando non si dispone di una classe di dati collegata al modulo è possibile implementare vincoli dipendenti in forme così:

$startRangeCallback = function ($object, ExecutionContextInterface $context) use ($form) 
    { 
     $data = $form->getData(); 
     $rangeEnd = $data['range_end']; 
     if($object && $rangeEnd){ 
      if ($object->getTimestamp() > $rangeEnd->getTimestamp()) { 
       $context->addViolation('Start date should be before end date!', array(), null); 
      } 
     } 

    }; 

    $form->add('range_start', 'bootstrap_datepicker', array(
      'format' => 'dd-MM-yyyy', 
      'required' => false, 
      'attr' => array('class' => "col-xs-2"), 
      'calendar_weeks' => true, 
      'clear_btn' => true, 
      'constraints' => array(
       new Callback(array($startRangeCallback)), 
      ) 
     ) 
    ); 

    $form->add('range_end', 'bootstrap_datepicker', array(
      'format' => 'dd-MM-yyyy', 
      'required' => false, 
      'attr' => array('class' => "col-xs-2"), 
      'calendar_weeks' => true, 
      'clear_btn' => true, 

     ) 
    ); 
+0

e cosa succede se devo accedere anche a entityManger? –

5

questo è il modo che ho fatto nel mio vincoli di validazione, per verificare la validità della carta di credito con le proprietà del mese e dell'anno di scadenza.

In questa classe, controllo il valore della proprietà expirationYear e lo confronta con il valore di expirationMonth proprietà ottenuta da contextObject.

/** 
* Method to validate 
* 
* @param string         $value  Property value  
* @param \Symfony\Component\Validator\Constraint $constraint All properties 
* 
* @return boolean 
*/ 
public function validate($value, Constraint $constraint) 
{ 
    $date    = getdate(); 
    $year    = (string) $date['year']; 
    $month    = (string) $date['mon']; 

    $yearLastDigits  = substr($year, 2); 
    $monthLastDigits = $month; 
    $otherFieldValue = $this->context->getRoot()->get('expirationMonth')->getData(); 

    if (!empty($otherFieldValue) && ($value <= $yearLastDigits) && 
      ($otherFieldValue <= $monthLastDigits)) { 
     $this->context->addViolation(
      $constraint->message, 
      array('%string%' => $value) 
     );    
     return false;    
    } 

    return true; 
} 

Naturalmente, è necessario autorizzare i vincoli di classe e di proprietà nel metodo getTargets, formano il file vincolo principale.

/** 
* Get class constraints and properties 
* 
* @return array 
*/ 
public function getTargets() 
{ 
    return array(self::CLASS_CONSTRAINT, self::PROPERTY_CONSTRAINT); 
} 

Ulteriori spiegazioni e completo tutorial qui: http://creativcoders.wordpress.com/2014/07/19/symfony2-two-fields-comparison-with-custom-validation-constraints/

3

Io suggerirei usando Expression constraint. Questo vincolo può essere applicato sul campo modulo o (preferibilmente) nell'entità:

/** 
    * @var int 
    * @Assert\Type(type="integer") 
    */ 
    private $amountGiftCards25; 

    /** 
    * @var int 
    * @Assert\Type(type="integer") 
    * @Assert\Expression(expression="this.getAmountGiftCards25() > 0 or value > 0", message="Please choose amount of gift cards.") 
    */ 
    private $amountGiftCards50; 
Problemi correlati