【问题标题】:symfony2 apply transformer to entity form field - empty array?symfony2 将转换器应用于实体表单字段 - 空数组?
【发布时间】:2013-07-20 02:26:15
【问题描述】:

我正在尝试让 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 集合。

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

【问题讨论】:

    标签: symfony transformer


    【解决方案1】:

    我从来没有找到一种方法来实现我正在尝试做的事情。但是,我使用的解决方法如下所述。

    对于表单类型类,我使用了表单事件(symfony2 book),并将boatId(帆对应的)保存在控制器的parts对象中,如下所示:

    $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';
    }
    

    我还需要在Mainsail 类中添加displayString 属性(我只添加了一个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 %}
    

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

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

    【讨论】:

      猜你喜欢
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-30
      • 1970-01-01
      • 1970-01-01
      • 2012-09-24
      • 2012-11-10
      相关资源
      最近更新 更多