问题 构建一个表单,其中包含一个doctrine集合中每个实体的复选框


我正在为过滤的实体集合显示一个html表,我想在每一行中显示一个复选框作为表单的一部分,该表单将选定的实体添加到会话变量中。

我认为每个复选框应该有实体id作为其值,我将从表单字段数据中获取一个id数组(好的,所以值应该是对实体的间接引用,但是为了简单)。

我尝试创建一个带有单个实体类型字段的表单Type,映射到实体的id属性并嵌入另一个具有集合类型字段的表单Type中。

class FooEntitySelectByIdentityType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('foo_id', 'entity', array(
            'required'  => false,
            'class'    => 'MeMyBundle:FooEntity',
            'property' => 'id',
            'multiple' => true,
            'expanded' => true
        ));
    }

# ...

class FooEntitySelectionType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('identity', 'collection', array(
            'type'   => new FooEntitySelectByIdentityType,
            'options'  => array(
                'required' => false,
                'multiple' => true,
                'expanded' => true,
                'attr'     => array('class' => 'foo')
            ),
        ));
    }

# ...

在控制器中,使用一组实体作为初始数据创建表单

$form = $this
    ->createForm(
        new \Me\MyBundle\Form\Type\FooEntitySelectionType,
        $collection_of_foo
    )
    ->createView()
;

呈现表单时,标识字段有一个标签,但没有窗口小部件。

甚至可以以这种特定方式使用实体和集合类型字段吗? 如果是这样,我可能做错了什么?


10281
2018-02-01 02:31


起源



答案:


我想这会回答你的问题。

忘了 FooEntitySelectionType。添加一个 property_path 字段选项 FooEntitySelectByIdentityType 并设置 data_class 选项 null

class FooEntitySelectByIdentityType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('foo_id', 'entity', array(
            'required'      => false,
            'class'         => 'MeMyBundle:FooEntity',
            'property'      => 'id',
            'property_path' => '[id]', # in square brackets!
            'multiple'      => true,
            'expanded'      => true
        ));
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class'      => null,
            'csrf_protection' => false
        ));
    }

# ...

并在你的控制器中,构建 FooEntitySelectByIdentityType

$form = $this
    ->createForm(
        new \Me\MyBundle\Form\Type\FooEntitySelectByIdentityType,
        $collection_of_foo
    )
    ->createView()
;

然后在接收POSTed数据的控制器动作中:

$form = $this
    ->createForm(new \Me\MyBundle\Form\Type\FooEntitySelectByIdentityType)
;
$form->bind($request);
if ($form->isValid()) {
    $data = $form->getData();
    $ids  = array();
    foreach ($data['foo_id'] as $entity) {
        $ids[] = $entity->getId();
    }
    $request->getSession()->set('admin/foo_list/batch', $ids);
}

最后,在你的树枝模板中:

{# ... #}
{% for entity in foo_entity_collection %}
    {# ... #}

    {{ form_widget(form.foo_id[entity.id]) }}

    {# ... #}

8
2018-02-01 19:11



这样可行!整个方法的缺点是 $form->getData() 返回一个包含实体集合而不是普通整数id的数组,但我认为好处是没有无效的id保存到会话中。谢谢@jah! - jah
请注意,如果您尝试使用字符串作为标识符,则此方法不起作用。该 EntityChoiceList 然后将为孩子和孩子创建基于整数的索引 form_widget call会抛出异常。 :( - althaus
我也遇到了这个麻烦。有没有更简单的方法来解决这个简单的问题? - Anh Nguyen
对于许多实体,这个解决方案非常慢,请参阅我的另一个问题 stackoverflow.com/questions/42469902/... - snoop168


答案:


我想这会回答你的问题。

忘了 FooEntitySelectionType。添加一个 property_path 字段选项 FooEntitySelectByIdentityType 并设置 data_class 选项 null

class FooEntitySelectByIdentityType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('foo_id', 'entity', array(
            'required'      => false,
            'class'         => 'MeMyBundle:FooEntity',
            'property'      => 'id',
            'property_path' => '[id]', # in square brackets!
            'multiple'      => true,
            'expanded'      => true
        ));
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class'      => null,
            'csrf_protection' => false
        ));
    }

# ...

并在你的控制器中,构建 FooEntitySelectByIdentityType

$form = $this
    ->createForm(
        new \Me\MyBundle\Form\Type\FooEntitySelectByIdentityType,
        $collection_of_foo
    )
    ->createView()
;

然后在接收POSTed数据的控制器动作中:

$form = $this
    ->createForm(new \Me\MyBundle\Form\Type\FooEntitySelectByIdentityType)
;
$form->bind($request);
if ($form->isValid()) {
    $data = $form->getData();
    $ids  = array();
    foreach ($data['foo_id'] as $entity) {
        $ids[] = $entity->getId();
    }
    $request->getSession()->set('admin/foo_list/batch', $ids);
}

最后,在你的树枝模板中:

{# ... #}
{% for entity in foo_entity_collection %}
    {# ... #}

    {{ form_widget(form.foo_id[entity.id]) }}

    {# ... #}

8
2018-02-01 19:11



这样可行!整个方法的缺点是 $form->getData() 返回一个包含实体集合而不是普通整数id的数组,但我认为好处是没有无效的id保存到会话中。谢谢@jah! - jah
请注意,如果您尝试使用字符串作为标识符,则此方法不起作用。该 EntityChoiceList 然后将为孩子和孩子创建基于整数的索引 form_widget call会抛出异常。 :( - althaus
我也遇到了这个麻烦。有没有更简单的方法来解决这个简单的问题? - Anh Nguyen
对于许多实体,这个解决方案非常慢,请参阅我的另一个问题 stackoverflow.com/questions/42469902/... - snoop168


如果有人正在为Symfony> = 2.3寻找解决方案

你必须改变这个:

    $data = $form->getData();
    $ids  = array();
    foreach ($data['foo_id'] as $entity) {
        $ids[] = $entity->getId();
    }

对此:

    $data = $form['foo_id']->getData();
    $ids = array();
    foreach ($data as $entity) {
        $ids[] = $entity->getId();
    }

3
2018-04-12 09:23





我创造了一个 symfony捆绑 用于以可配置的方式将实体集合呈现为复选框表。虽然问这个问题已经有一段时间了,但我希望这可以帮助其他人解决同样的问题。


2
2018-04-18 14:00



我正在使用这个Bundle,我不得不说这很酷!谢谢! - Muc
尝试一次显示多达1000条记录时,捆绑包的性能如何?我打算使用数据表服务器端处理来限制每个页面加载显示的记录数量,但似乎当我使用上面的其他答案时,我需要创建我的实体类型,其中包含所有可能的选项,而不仅仅是最初仅限于第一页记录。我遇到与此相关的性能问题。 - snoop168