4

大家好(请原谅我的英语)。

我想做一个应用程序,它需要允许用户必须在表格上填写他们的个人数据、他们的孩子、孙子和曾孙(一个小家谱)。

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 表单来完成,或者我是否必须查看其他替代方案。如果这是可能的,我怎么能做到这一点,我怎么能限制表单只呈现我需要的四个级别(我、我的孩子、我的孙子和我的曾孙)?

我希望问题已被理解。

提前致谢。

4

4 回答 4

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
        ));
    }
}

这未经测试。

于 2014-04-05T11:10:33.547 回答
1

我遇到了同样的问题并尝试了此处提供的解决方案。它们具有显着的缺点,例如深度限制和性能开销——即使没有提交数据,您也总是创建表单对象。

为了解决这个问题,我为 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
                ));
        }
    });

}

我希望这对将来遇到此问题的人有所帮助

于 2016-09-07T13:27:00.267 回答
0

感谢费迪纳特的回答!!

我没有按照您提出的方式解决问题,但是这种方法对我有所帮助。我在 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,)
            );
        }
    }
}
于 2014-04-07T09:54:25.660 回答
0

Ferdynator,谢谢你的回答。我想根据你的决定提出我的决定:

    公共函数 setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(数组(
            'data_class' => 'Anything\YourBundle\Entity\Person',
            'recursionLevel' => 4
        ));
    }

    公共函数 buildForm(FormBuilderInterface $builder, array $options)
    {
        // ...
        if (--$options['recursionLevel'] > 0) {
            $builder->add('children', 'collection', array(
                '类型' => $childType,
                'allow_add' => 真,
                'by_reference' => 假,
                '选项' => [
                    'recursionLevel' => $options['recursionLevel']
                ],
            ));
        }
    }

它解决了我们的问题。

于 2014-12-17T14:12:02.910 回答