大家好(请原谅我的英文)。
我想做一个应用程序,需要允许用户必须在表单上填写他们的个人数据,他们的子女,孙子女和曾孙子(一个小家谱)。
class Person
{
/**
* @var int
*
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @var string
*
* @ORM\Column(type="string")
*/
private $firstname;
/**
* @var string
*
* @ORM\Column(type="string")
*/
private $lastname;
/**
* @var \DateTime
*
* @ORM\Column(type="datetime")
*/
private $dateOfBirth;
/**
* @var Person
*
* @ORM\ManyToMany(targetEntity="Person")
*/
private $children;
public function __construct()
{
$this->children = new ArrayCollection();
}
}
}
在PersonType类中,我执行以下操作:
class PersonType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('firstname');
$builder->add('lastname');
$builder->add('dateOfBirth');
$builder->add('children', 'collection', array(
'type' => new PersonType(),
'allow_add' => true,
'by_reference' => false,)
);
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Anything\YourBundle\Entity\Person'
));
}
/**
* @return string
*/
public function getName()
{
return 'person';
}
}
通过这种方式,我在控制器中使用PersonType,如下所示:
public function newAction()
{
$entity = new Person();
$form = $this->createForm(new PersonType(), $entity, array(
'action' => $this->generateUrl('person_create'),
'method' => 'POST',
));
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
但问题是当我请求此操作的url,并且必须呈现此操作的视图时,存在一个问题,因为没有给出响应,因为它处于无限循环中(我认为是原因)。我想知道是否可以使用Symfony表单,或者如果我必须查看其他替代方案。如果这是可能的,我怎么能这样做,我怎么能限制表格只提供我需要的四个级别(我,我的孩子,我的孙子孙女和我的曾孙子)??
我希望能够理解这个问题。
提前致谢。
答案 0 :(得分:2)
您可以在表单中添加一个自定义参数,指示当前的递归级别。 要存档,首先需要实现一个新选项:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Anything\YourBundle\Entity\Person',
'recursionLevel' => 4
));
}
现在,您可以使用buildForm
方法更新此值:
public function buildForm(FormBuilderInterface $builder, array $options)
{
// ...
if (--$options['recursionLevel'] > 0) {
$resolver = new OptionsResolver();
$resolver->setDefaults(
$options
);
$childType = new PersonType();
$childType->setDefaultOptions($resolver);
$builder->add('children', 'collection', array(
'type' => $childType,
'allow_add' => true,
'by_reference' => false
));
}
}
未经测试。
答案 1 :(得分:0)
感谢Ferdynator的回答!!
我没有以你提出的方式解决问题,但这种方法对我有所帮助。我在Person表单的构造函数中传递了递归级别,因此,我可以知道何时必须停止:
class PersonType extends AbstractType
{
private $recursionLevel;
public function __construct( $recursionLevel ){
$this->recursionLevel = $recursionLevel;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
if($this->recursionLevel > 0)
{
$builder->add('children', 'collection', array(
'type' => new PersonType(--$this->recursionLevel),
'allow_add' => true,
'by_reference' => false,)
);
}
}
}
答案 2 :(得分:0)
Ferdynator,谢谢你的回答。我想根据你的决定提出我的决定:
public function setDefaultOptions(OptionsResolverInterface $resolver) { $resolver->setDefaults(array( 'data_class' => 'Anything\YourBundle\Entity\Person', 'recursionLevel' => 4 )); } public function buildForm(FormBuilderInterface $builder, array $options) { // ... if (--$options['recursionLevel'] > 0) { $builder->add('children', 'collection', array( 'type' => $childType, 'allow_add' => true, 'by_reference' => false, 'options' => [ 'recursionLevel' => $options['recursionLevel'] ], )); } }
它解决了我们的问题。
答案 3 :(得分:0)
我遇到了同样的问题并尝试了此处提供的解决方案。 它们具有明显的缺点,如深度限制和性能开销 - 即使没有提交数据,也总是创建表单对象。
我为克服这个问题所做的是为FormEvents :: PRE_SUBMIT事件添加一个监听器,并在有数据需要解析的情况下动态添加集合类型字段。
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('content');
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$node = $event->getData();
$form = $event->getForm();
if (!$node) {
return;
}
if(sizeof(@$node['children'])){
$form->add('children', CollectionType::class,
array(
'entry_type' => NodeType::class,
'allow_add' => true,
'allow_delete' => true
));
}
});
}
我希望这可以帮助将来有这个问题的人