2013-06-18 5 views
2

Я пытаюсь получить dataTransformer работать на поле объекта в Symfony 2.symfony2 применить трансформатор к форме формы объекта - пустой массив?

контекст:

  • форма отображает паруса, которые пользователь может выбрать (чекбоксы)

  • это первый шаг в многоэтапном процессе упорядочивания парусов (в последующих шагах отображаются параметры, доступные для каждого паруса, цвета и т. д.)

Это моя форма тип класса:

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\OptionsResolver\OptionsResolverInterface; 
use Symfony\Component\Form\FormBuilderInterface; 
use Co\QuoteBundle\Form\DataTransformer\SailCollectionToStringsTransformer; 

class PartsTypeStep1 extends AbstractType { 

public function setDefaultOptions(OptionsResolverInterface $resolver) 
{ 
    $resolver->setDefaults(array(
     'data_class' => 'Co\QuoteBundle\Entity\Parts',)); 

    $resolver->setRequired(array('sailsAvailable', 'em')); 
} 

public function buildForm(FormBuilderInterface $formBuilder, array $options) 
{   
    $transformer = new SailCollectionToStringsTransformer($options['em']); 

    $formBuilder->add(
     $formBuilder->create('mainsailparts', 'entity', array(
      'class' => 'CoQuoteBundle:Mainsail', 
      'choices' => $options['sailsAvailable']['mains'], 
      'multiple' => true, 
      'expanded' => true, 
      'label' => 'Mainsails',)) 
     ->addModelTransformer($transformer)); //line 58 
} 

public function getName() { 
    return 'partsStep1'; 
} 
} 

Вышеперечисленные работы без ошибок, но не выводит преобразованные данные. Мнение:

__ Race main 
__ Cruising main 

(__ обозначает флажком)

Однако мнение, что я хочу:

__ Race main ($1400) 
__ Cruising main ($800) 

трансформатор у меня есть это:

use Symfony\Component\Form\DataTransformerInterface; 
use Symfony\Component\Form\Exception\TransformationFailedException; 
use Doctrine\Common\Persistence\ObjectManager; 
use Co\QuoteBundle\Entity\Sail; 
use Doctrine\Common\Collections\ArrayCollection; 

class SailCollectionToStringsTransformer implements DataTransformerInterface 
{ 
/** 
* @var ObjectManager 
*/ 
private $om; 

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

/** 
* Transforms a collection of sails to a collection of strings. 
* @param ISail|null $sail 
* @return string 
*/ 
public function transform($sailCollection) 
{ 
    if (null === $sailCollection) { 
     return null; 
    } 

    $labels = new ArrayCollection(); 

    foreach($sailCollection as $sail){ 
     $labels[] = $sail->getName().' ($'.$sail->getBuildPrice().')'; 
    } 

    return $labels; 
} 

//reverse transformer... not the issue (yet) because the forward transformer doesn't work 

} 

Когда запуская это через отладчик netbeans, пустым массивом передается трансформатор. Однако, если я меняю строку 58 на ->addViewTransformer($transformer)); и отлаживаю, она правильно передает два логических значения с идентификатором паруса в качестве ключей массива к трансформатору. К сожалению, я не могу использовать ViewTransformer, потому что это больше не содержит исходные строки для изменения.

Почему массив ArrayCollection, который должен содержать основные паруса, передается трансформатору в виде пустого ArrayCollection? Функция возвращает пустую коллекцию $labels.

Я не уверен, что я делаю неправильно ... Помощь очень ценится !!!! Спасибо.

ответ

1

Я так и не нашел способ реализовать то, что я пытался сделать. Однако обходной путь, который я использовал, описан ниже.

для класса формы типа, я использовал форму событие (symfony2 book), и я спас boatId (что паруса соответствуют) в части объекта в контроллере, например, так:

$partsObject = new Parts($boat->getId()); 
$form = $this->createForm(new PartsTypeStep1(), $partsObject, array(
       'em' => $this->getDoctrine()->getManager())); 

Тип формы класс теперь выглядит следующим образом:

use Symfony\Component\Form\AbstractType; 
use Symfony\Component\OptionsResolver\OptionsResolverInterface; 
use Symfony\Component\Form\FormBuilderInterface; 
use Symfony\Component\Form\FormEvents; 
use Symfony\Component\Form\FormEvent; 
use Doctrine\ORM\EntityRepository; 

class PartsTypeStep1 extends AbstractType { 

public function setDefaultOptions(OptionsResolverInterface $resolver) 
{ 
    $resolver->setDefaults(array(
     'data_class' => 'Co\QuoteBundle\Entity\Parts',)); 

    $resolver->setRequired(array('em')); 
} 

public function buildForm(FormBuilderInterface $formBuilder, array $options) 
{    
    $factory = $formBuilder->getFormFactory(); 
    $em = $options['em']; 

    $formBuilder->addEventListener(
     FormEvents::PRE_SET_DATA, 
     function(FormEvent $event) use($factory, $em){ 
      $form = $event->getForm(); 
      $data = $event->getData(); 

      if (!$data || !$data->getDateTime()) { 
       return; 
      } 
      else { 
       $boatClass = $data->getBoatId(); 

       $formOptions = array(
          'class' => 'CoQuoteBundle:Mainsail', 
          'multiple' => true, 
          'expanded' => true, 
          'property' => 'displayString', 
          'label' => 'Mainsails', 
          'query_builder' => function(EntityRepository $er) use ($boatClass) { 
           return $er->createQueryBuilder('m') 
             ->where('m.boatType = :boatClass') 
             ->setParameter('boatClass', $boatClass); 
          }, 
         ); 
       $form->add($factory->createNamed('mainsailparts', 'entity', null, $formOptions)); 

       } 
     } 
    ); 

} 

public function getName() { 
    return 'partsStep1'; 
} 

Я также необходимо добавить displayString свойство в Mainsail классе (я только добавил добытчик, а не фактической переменной для строки). Так Mainsail класса теперь это:

public function getDisplayString(){ 
    return $this->name . ' - ' . $this->descr . ' ($' . $this->buildPrice . ')'; 
} 

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

  {% if form.mainsailparts|length > 0 %} 
       <div class="groupHeading">{{ form_label(form.mainsailparts) }}</div> 
       {% for child in form.mainsailparts %} 
        {# render each checkbox .... #} 

       {% endfor %} 
      {% else %} 
       {% do form.mainsailparts.setRendered %} 
      {% endif %} 

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

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