Symfony 2.7:从表单生成器中自动填充表单字段

Symfony 2.7: Automatically Populate Form Field from Within Form Builder

我有一个名为 HoursSpecial 的实体,它与一个名为 HoursArea 的实体有外键关系。每个 HoursSpecial 都属于一个 HoursArea。当我通过 HoursSpecialType 创建新的 HoursSpecial 时,我希望表单字段自动填充 HoursArea 字段。

我知道你在想什么,只需在我的控制器方法中做这样的事情:

$form->add('area', 'hidden', array('data'=>$area));

这很好,但我需要创建一个 DataTransformer 来在区域 ID 和实际区域实体之间切换。所以我必须使用转换器在我的 HoursSpecialType 中声明我的 HoursArea 字段:

    $builder
        ...
        ->add('area', 'hidden')
    ;

    $builder->get('area')->addModelTransformer(new HoursAreaToIntTransformer($this->manager));

现在,我不能简单地将我的 HoursArea 实体输入到表单中。有什么有效的方法可以做到这一点吗?

我已经翻阅了 Symfony 关于 How to Dynamically Modify Forms Using Form Events 的文档,但我无法弄清如何从表单构建器外部动态传递 HoursArea 实体。也许我只是错过了什么?

更新

根据@Ryan 下面的答案(建议 #1)的建议,我创建了自定义类型 HiddenHoursAreaType:

// AppBundle\Form\Type\HideenHoursAreaType.php
class HiddenHoursAreaType extends AbstractType
{
//need to instantiate HoursAreaToIntTransformer
private $manager;

public function __construct(ObjectManager $manager)
{
    $this->manager = $manager;
}

/**
 * @param FormBuilderInterface $builder
 * @param array $options
 */
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $transformer = new HoursAreaToIntTransformer($this->manager);
    $builder->addModelTransformer($transformer);
}



public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults(array(
        'data_class' => null,
        'compound' => true  //this should be FALSE as there are no children
    ));
}

/**
 * 
 * the return value of the getParent function indicates that you're extending the choice field type. 
 * This means that, by default, you inherit all of the logic and rendering of that field type.
 */
public function getParent()
{
    return 'hidden';
}

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

我已将我的转换器添加到自定义类型中 class。这是变压器 class:

// AppBundle\Form\DataTransformer;
class HoursAreaToIntTransformer implements DataTransformerInterface
{
    private $manager;

    public function __construct(ObjectManager $manager)
    {
        $this->manager = $manager;
    }

    /**
     * Transforms an object (HoursArea) to a string (number).
     *
     * @param  Issue|null $issue
     * @return string
     */
    public function transform($area)
    {
        if (null === $area) {
            return '';
        }

        return $area->getId();
    }

    /**
     * Transforms a string (number) to an object (HoursArea).
     *
     * @param  string $areaId
     * @return HoursArea|null
     * @throws TransformationFailedException if object (HoursArea) is not found.
     */
    public function reverseTransform($areaId)
    {
        // no area number? It's optional, so that's ok
        if (!$areaId) {
            return;
        }

        $area = $this->manager
            ->getRepository('AppBundle:HoursArea')
            // query for the issue with this id
            ->find($areaId)
        ;

        if (null === $area) {
            // causes a validation error
            // this message is not shown to the user
            // see the invalid_message option
            throw new TransformationFailedException(sprintf(
                'An area with number "%s" does not exist!',
                $areaId
            ));
        }

        return $area;
    }
}

在我的控制器中,我创建了带有自定义类型字段的表单:

$form = $this->createForm(new HoursSpecialType($this->getDoctrine()->getManager()), $entity, array(
        'action' => $this->generateUrl('hoursspecial_postcreate'),
        'method' => 'POST',
    ));
    $form->add('eventDate', 'hidden', array('data'=>$dateString));
    $form->add('area', new \AppBundle\Form\Type\HiddenHoursAreaType($this->getDoctrine()->getManager()), array(
        'data'=>$area,
        'invalid_message'=>'Area field not converted proerly'
    ));

    $form->add('submit', 'submit', array('label' => 'Create'));

多亏了转换器和自定义类型,表单现在可以正确地将 HoursArea 实体转换为隐藏字段中人口的整数。

现在的问题是,在提交表单时,整数没有转换回 HoursArea 对象。我知道这是因为我在提交时得到了 'invalid_message'。

最终更新

未正确插入 HoursArea id 的原因与

'compound' => true

我在自定义类型中的设置。我假设它正在寻找子字段并且没有找到任何......它不应该有因为有 none!

  1. 您可以为其创建自定义类型并在自定义类型的 buildForm() 中添加 addModelTransformer() 调用,但仍显式传递数据。因此,您的 $form->add('area', 'hidden', array('data'=>$area)) 将变为 $form->add('area', new HiddenHoursAreaType(), array('data'=>$area)),其中 HiddenHoursAreaType::getParent() 将是 hidden 类型。

  2. 您可以在 POST_SET_DATA 侦听器中设置数据。

  3. 您可以在 buildForm() 中获取 $options['data'] 值并显式传入 HoursArea ID。

    /** @var HoursSpecial $hoursSpecial Prepopulated in controller */
    $hoursSpecial = $options['data']
    $builder->add('area', 'hidden', ['data' => $hoursSpecial->getHoursArea()->getId()])