2

我正在尝试让 dataTransformer 在 symfony 2 中的实体字段上工作。

语境:

  • 表单显示用户可以选择的帆(复选框)

  • 这是多步帆订购流程的第一步(后续步骤显示每个帆可用的选项、颜色等)

这是我的表单类型类:

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));并进行调试,它会正确地将两个布尔值与帆 id 作为数组键传递给转换器。不幸的是,我不能使用,ViewTransformer因为它不再包含要更改的原始字符串。

为什么应该包含主帆的 ArrayCollection 会作为空的 ArrayCollection 传递给变压器?该函数返回一个空集合$labels

我不确定我做错了什么......非常感谢帮助!!!!谢谢。

4

1 回答 1

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(我只添加了一个 getter,而不是字符串的实际变量)。所以这个Mainsail类现在有这个:

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

我在使用此解决方法时遇到的唯一问题是,如果查询返回空结果会发生什么情况,因为无论是否有要呈现的复选框,twig 都会自动呈现表单标签('Mainsails')。我像这样解决了这个问题:

            {% 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 %}

我不知道在这种情况下这是否是推荐的解决方案,但它确实适用于表单验证(如果没有选择帆,至少不允许进展,我不需要更严格的东西)。

我不会将此标记为答案,因为它没有回答问题(如何将转换器应用于实体字段),但对于处理相同问题的任何人来说,它都是一种解决方法。

于 2013-07-19T18:26:15.863 回答