Symfony3:填充了对象数组的选择类型字段

Eve*_*Eve 6 entity object choice choicefield symfony

我有一个实体Product.我的产品可以有多个不同语言的名称.法语名称,英语名称等.我不想使用自动翻译.

用户必须在"产品"表单中写入名称并选择相应的语言.由于添加按钮,他可以根据需要添加许多名称.

所有语言都是由admin用户创建的(另一种形式).因此,Language也是一个具有名称(例如:英语)和代码(例如EN)的实体.

我创建了ProductName具有名称和语言的Entity (符合用户在Product表单中写入的内容).

在这种情况下,我不需要将实体ProductName与实体相关联Language.我只想要语言代码.所以,在我的ProductName实体中,我有这个属性:

/**
 * @ORM\Column(name="Language_Code", type="string", length=2)
 */
private $language;
Run Code Online (Sandbox Code Playgroud)

我的产品表单(ProductType)有一个CollectionType字段,以便添加多个名称.

// Form/ProductType.php

    ->add('infos',      CollectionType::class, array(
        'entry_type'    => ProductInfosType::class,
        'allow_add'     => true,
        'allow_delete'  => true,
        'prototype'     => true,
        'label'         => false,
        'mapped'        => false
    ))
Run Code Online (Sandbox Code Playgroud)

ProductInfosType表单有2个字段:

// Form/ProductInfosType.php

        ->add('name',           TextType::class, array(
            'attr'              => array('size' => 40)
        ))
        ->add('language',       EntityType::class, array(
            'placeholder'       => '',
            'class'             => 'AppBundle:Language',
            'choice_label'      => 'code',
            'attr'              => array('class' => 'lang'),
            'query_builder'     => function (EntityRepository $er) {
                return $er->createQueryBuilder('l')->orderBy('l.code', 'ASC');
            }
        ))
Run Code Online (Sandbox Code Playgroud)

因此,当我进入表单页面时,我有一个包含输入文本字段(名称)和选择字段(语言)的块.选择字段是这样的:

<select id="product_infos_0_language" required="required" name="product[infos][0][language]">
    <option value=""></option>
    <option value="DE">DE</option>
    <option value="EN">EN</option>
    <option value="ES">ES</option>
    <option selected="selected" value="FR">FR</option>
</select> 
Run Code Online (Sandbox Code Playgroud)

在这一点上,一切都运作良好.我创建了一个添加按钮,以便用户可以添加其他名称等...

但是,当我提交表单时,当我在ProductController中检查表单数据时,我注意到它与我想要存储在数据库中的内容不对应.

print_r($form->get('infos')->getData());

// returns :
Array
(
    [0] => AppBundle\Entity\ProductName Object
        ( 
            [language:AppBundle\Entity\ProductName:private] => AppBundle\Entity\Language Object
                (
                    [code:AppBundle\Entity\Language:private] => FR
                    [name:AppBundle\Entity\Language:private] => Français
                )

            [name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin
        )
)
Run Code Online (Sandbox Code Playgroud)

我想要的是:

Array
(
    [0] => AppBundle\Entity\ProductName Object
        ( 
            [language:AppBundle\Entity\ProductName:private] => FR    
            [name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin
        )
)
Run Code Online (Sandbox Code Playgroud)

我不想要语言对象,而是直接使用语言代码!

这就是为什么我认为我不应该使用EntityFieldProductNameType形式而是ChoiceType字段.

如何在选择字段中加载存储在db中的所有语言? 我希望这个解释更容易理解;-)

Eve*_*Eve 7

我找到了解决方案,感谢这篇文章:在Symfony 2.8/3.0中将数据传递给buildForm()

ProductController.php:将自定义数据作为createForm()方法中的选项传递.

// ...

// build the form
$em = $this->getDoctrine()->getManager();
$product = new Product();
$languages = $em->getRepository('AppBundle:Language')->findAllOrderedByCode();

$form = $this->createForm(ProductType::class, $product, array(
    'languages' => $languages
));
Run Code Online (Sandbox Code Playgroud)

ProductType表单:在选项解析器中传递自定义数据

public function configureOptions(OptionsResolver $resolver) {
    $resolver->setDefaults(array(
        'data_class' => 'AppBundle\Entity\Product',
        'languages'  => null
    ));
}
Run Code Online (Sandbox Code Playgroud)

然后,在buildForm()函数中,entry_options在CollectionType字段中添加一个选项:

$builder->add('infos',  CollectionType::class, array(
    'entry_type'    => ProductInfosType::class,
    'entry_options' => array('languages' => $options['languages']),
    'allow_add'     => true,
    'allow_delete'  => true,
    'prototype'     => true,
    'label'         => false,
    'by_reference'  => false
));
Run Code Online (Sandbox Code Playgroud)

ProductInfosType表单:在选项解析器中传递自定义数据(与ProductForm中的完全相同)

public function configureOptions(OptionsResolver $resolver) {
    $resolver->setDefaults(array(
        'data_class' => 'AppBundle\Entity\ProductName',
        'languages'  => null
    ));
}
Run Code Online (Sandbox Code Playgroud)

现在,您有两种选择:要么您希望表单返回实体或简单字符串.

在我的例子中,我只想要语言代码(如FR,EN等).

案例1:在发布表单时仅返回语言代码:

// Form/ProductInfosType.php

// ...

// Convert array of objects in an array of strings
$choices = array();
foreach ($options['languages'] as $lang) {
    $code = $lang->getCode();
    $choices[$code] = $code;
}

$builder->add('language', ChoiceType::class, array(
    'placeholder'       => '',
    'choices'           => $choices
));

// returns :
Array
(
    [0] => AppBundle\Entity\ProductName Object
        ( 
            [name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin
            [language:AppBundle\Entity\ProductName:private] => FR    
        )
)
Run Code Online (Sandbox Code Playgroud)

案例2:发布表单时返回语言实体:

// Form/ProductInfosType.php

// ...

$builder->add('language', ChoiceType::class, array(
    'placeholder'       => '',
    'choices'           => $options['languages'],
    'choice_label'      => 'code',
    'choice_value'      => 'code'
));

// returns :
Array
(
    [0] => AppBundle\Entity\ProductName Object
        ( 
            [name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin
            [language:AppBundle\Entity\ProductName:private] => AppBundle\Entity\Language Object
                (
                    [code:AppBundle\Entity\Language:private] => FR
                    [name:AppBundle\Entity\Language:private] => Français
                )    
        )
)
Run Code Online (Sandbox Code Playgroud)

使用此解决方案,我们不需要将表单创建为服务,以便将实体管理器作为参数传递.所有都在控制器和表单选项中进行管理.