Symfony2 проверяет ограничения полей поля перед преобразованием данных

Я создал форму, которая требует трансформатора данных, но попала в одиночную проблему: я преобразовываю данные путем взрыва строки (строка должна быть разнесена на 3 части), все работает, если я поставлю правильную строку формата, но в противном случае она бросает ошибка внутри преобразователя данных, поскольку преобразование не может произойти, если задан неправильный формат строки (это ожидаемое поведение).

Итак, вопрос в том, есть способ проверить поле формы для правильной строки перед преобразованием данных? Я знаю, что преобразование данных по умолчанию происходит до проверки, но может быть, есть способ сделать это по-другому?

Я нашел одно решение, которое могло бы работать над этим потоком: Объединить ограничения и трансформаторы данных, но это похоже на грубое решение, кроме того, мне нужно перевести сообщение проверки, и мне бы очень хотелось это сделать, используя методы перевода по умолчанию для форм symfony (без использования услуги перевода)

Я подумал, а также кто-то из symfony IRC (Iltar) предложил сделать это с помощью событий, но я не уверен, как это сделать - как динамически подключать преобразователь данных к форме? Или, может быть, иначе?

Ответ 1

Возможно, слишком поздно, но в итоге мне это удается. Возможно, это поможет вам.

Вот мой 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();
    }
}

Ответ 2

Возможно, вы можете передать экземпляр вашей формы в ваш трансформатор. Если строка не анализируется правильно, просто добавьте в форму ошибку проверки:

<?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;
  }
}