2014-07-15 53 views
10

我已經創建了需要數據轉換的表單,但卻讓我陷入了單個問題:我通過爆炸字符串轉換數據(字符串應該被分解爲3部分),如果我提供正確的格式字符串,但否則會在數據轉換器中引發錯誤,因爲如果提供了錯誤的字符串格式(這是預期的行爲),則不會發生轉換。Symfony2表單字段約束驗證在數據轉換器之前

所以問題是有沒有辦法在數據轉換之前驗證表單字段的正確字符串?我知道默認情況下數據轉換髮生在驗證之前,但也許有其他方法可以做到這一點嗎?

我找到了一個解決方案,可能會在此線程工作:Combine constraints and data transformers, 但它看起來像粗糙的解決方案,除了我需要翻譯驗證消息,我真的想使用symfony的形式默認的翻譯方法做到這一點(不使用翻譯服務)

我想,也有人從symfony IRC(Iltar)建議通過使用事件來做到這一點,但我不知道如何去做到這一點 - 如何動態附加數據轉換器來形成字段?或者也許有其他方法?

+0

如果仍然沒有解決您的問題嘗試檢查此問題:http://stackoverflow.com/questions/25201919/apply-validation-before-data-transform –

+0

我很久以前就已經解決了這個問題,並且提供了一個類似於你所建議的解決方案,但是我留下了這個問題,因爲在我看來,這樣的解決方案體積龐大,並且違背瞭解耦代碼的symfony priciples,因爲我需要使用手動翻譯服務翻譯驗證消息。 –

回答

0

也許你可以將表單的實例傳遞給你的變換器。如果該字符串不正確地分析,只需添加一個驗證錯誤的形式,像這樣:

<?php 
// src/Acme/MyBundle/Form/DataTransformer/StringTransformer.php 
namespace Acme\MyBundle\Form\DataTransformer; 

use Symfony\Component\Form\DataTransformerInterface; 
use Symfony\Component\Form\Exception\TransformationFailedException; 
use Doctrine\Common\Persistence\ObjectManager; 
use Acme\MyBundle\Entity\MyEntity; 
use Acme\MyBundle\Entity\AnotherEntity; 
use Acme\MyBundle\Type\MyEntityType; 

class StringTransformer implements DataTransformerInterface 
{ 
    /** 
    * @var MyEntityType 
    */ 
    private $form; 

    /** 
    * @param ObjectManager $om 
    */ 
    public function __construct(MyEntityType $form) 
    { 
    $this->form = $form; 
    } 

    /** 
    * Transforms an object (entity) to a string (number). 
    * 
    * @param MyEntity|null $entity 
    * @return string 
    */ 
    public function transform($value) 
    { 
    // ... 
    } 

    /** 
    * Transforms a string (number) to an object (entity). 
    * 
    * @param string $number 
    * 
    * @return MyEntity|null 
    * 
    * @throws TransformationFailedException if object (entity) is not found. 
    */ 
    public function reverseTransform($value) 
    { 
    $collection = new ArrayCollection(); 

    try{ 
     $vals = explode(',', $value); 

     foreach($vals as $v){ 
     $entity = new AnotherEntity(); 
     $entity->setValue($v); 
     $collection->add($v); 
     } 

    } catch(\Exception $e){ 
     $this->form 
     ->get('my_location') 
     ->addError(new FormError('error message')); 
    } 

    return $collection; 
    } 
} 
6

這也許爲時已晚,但我最終還是設法做到這一點。 也許它會幫助你。

這裏是我的FormType:

class PersonType extends AbstractType{ 

    public function buildForm(FormBuilderInterface $builder, array $options){ 
     $builder->add('mother', 'personSelector', array('personEntity' => $options['personEntity'])); 

    } 
} 

這裏是我的CustomField在哪裏驗證:

class PersonSelectorType extends AbstractType{ 

    public function buildForm(FormBuilderInterface $builder, array $options){ 
     $transformer = new PersonByFirstnameAndLastnameTransformer($this->entityManager,$options); 
     $builder->addModelTransformer($transformer); 
     $builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmitForm')); 
    } 

    public function onPreSubmitForm(FormEvent $event){ 
     $mother  = $event->getData(); 
     $form  = $event->getForm(); 
     $options = $form->getConfig()->getOptions(); 
     if (!empty($mother)){ 
      preg_match('#(.*) (.*)#', $mother, $personInformations); 
      if (count($personInformations) != 3){ 
       $form->addError(new FormError('[Format incorrect] Le format attendu est "Prénom Nom".')); 
      }else{ 
       $person = $this->entityManager->getRepository($options['personEntity'])->findOneBy(array('firstname' => $personInformations[1],'lastname' =>$personInformations[2])); 
       if ($person === null) { 
        $form->addError(new FormError('Il n\'existe pas de person '.$personInformations[1].' '.$personInformations[2].'.')); 
       } 
      } 
     } 
    } 
} 

這裏是我的變壓器:

class PersonByFirstnameAndLastnameTransformer implements DataTransformerInterface{ 

    public function reverseTransform($firstnameAndLastname) { 
     if (empty($firstnameAndLastname)) { return null; } 
     preg_match('#(.*) (.*)#', $firstnameAndLastname, $personInformations); 
     $person = $this->entityManager->getRepository($this->options['personEntity'])->findOneBy(array('firstname' =>$personInformations[1],'lastname' =>$personInformations[2])); 
     if (count($personInformations) == 3){ 
      $person = $this->entityManager->getRepository($this->options['personEntity'])->findOneBy(array('firstname' =>$personInformations[1],'lastname' =>$personInformations[2])); 
     } 
     return $person; 
    } 

    public function transform($person) { 
     if ($person === null) { return ''; } 
     return $person->getFirstname().' '.$person->getLastname(); 
    } 
} 
+0

如果要在「PersonSelectorType」中針對特定表單元素進行驗證,您是否需要調用'$ event-> setData($ element)'? – thoroc