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!
您可以为其创建自定义类型并在自定义类型的 buildForm()
中添加 addModelTransformer()
调用,但仍显式传递数据。因此,您的 $form->add('area', 'hidden', array('data'=>$area))
将变为 $form->add('area', new HiddenHoursAreaType(), array('data'=>$area))
,其中 HiddenHoursAreaType::getParent()
将是 hidden
类型。
您可以在 POST_SET_DATA
侦听器中设置数据。
您可以在 buildForm()
中获取 $options['data']
值并显式传入 HoursArea
ID。
/** @var HoursSpecial $hoursSpecial Prepopulated in controller */
$hoursSpecial = $options['data']
$builder->add('area', 'hidden', ['data' => $hoursSpecial->getHoursArea()->getId()])
我有一个名为 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!
您可以为其创建自定义类型并在自定义类型的
buildForm()
中添加addModelTransformer()
调用,但仍显式传递数据。因此,您的$form->add('area', 'hidden', array('data'=>$area))
将变为$form->add('area', new HiddenHoursAreaType(), array('data'=>$area))
,其中HiddenHoursAreaType::getParent()
将是hidden
类型。您可以在
POST_SET_DATA
侦听器中设置数据。您可以在
buildForm()
中获取$options['data']
值并显式传入HoursArea
ID。/** @var HoursSpecial $hoursSpecial Prepopulated in controller */ $hoursSpecial = $options['data'] $builder->add('area', 'hidden', ['data' => $hoursSpecial->getHoursArea()->getId()])