使用EntityType显示选择项时,无法从Symfony表单保存实体

时间:2019-02-11 20:22:08

标签: symfony symfony-forms

我的symfony项目中有两个相关实体-使用Doctrine存储。一个实体是“广告商”,它具有ID和名称。另一个引起问题的实体是一个“报告”,它具有自己的ID以及一个名为“ advertiser_id”的字段。

在为Symfony表单添加广告商的报告时,我将EntityType用于Advertiser_id字段,以便可以显示选择的广告商。该部分的效果很好,但是当我尝试提交表单时,出现错误,因为它正在将Advertiser对象而不是广告商的ID传递给advertiser_id字段。

这是表单生成器中的内容:

$builder
    ->add('advertiser_id', EntityType::class, [
        'class'        => Advertiser::class,
        'query_builder' => $this->advertiserRepository->findAllNotDeletedUnpaginated(),
        'choice_label' => 'name',

    ])
    ->add('submit', SubmitType::class, [
        'label' => 'Submit',
    ])
;

提交表单时,出现以下错误: 类型为“整数”的预期参数,“ App \ Entity \ Advertiser”。

关于如何强制symfony仅尝试保存所选广告客户的ID而不是传递整个广告客户的想法?

  
    

更新:现在,我已经对其进行了重构,以便广告客户可以作为要报告的相关实体,我正在尝试找出如何使广告客户成为隐藏字段并且一无所获。

  

我已经使用回调转换器尝试了前面提到的iiirxs的代码-将'advertiser_id'更改为'advertiser'-但是我对此并不走运。我一直在阅读类似Symfony hiddenType using data_class for entity instead of transformer这样的帖子,但在该示例中,他们在获取$ options ['selected_course']的方式上很难获得“广告商”的价值。

当我尝试(出于测试目的)为广告客户硬编码1的值,然后将其放在表单上时,表单显示出来,但是提交时出现错误:

    $advertiser=1;

    $builder
        ->add('advertiser', HiddenType::class,['data' => $advertiser, 'data_class' => null])

提交表单时出现的错误是: 预期的参数类型为“ App \ Entity \ Advertiser或为null”,给出了“字符串”。

我很抱歉为此击败了一匹死马。这似乎应该是一件很普通/容易的事情,但是我很难找到如何使其成为隐藏字段的方法。任何想法将不胜感激!

2 个答案:

答案 0 :(得分:0)

问题是您尚未在报表实体中正确定义与Advertiser实体的关联。您应该已经定义了这样的关联:

// inside Report.php class

/**
 * @ORM\ManyToOne(targetEntity="App\Entity\Advertiser")
 */
private $advertiser;

而不是定义一个包含外键advertiser_id的字段。 Doctrine非常聪明,可以自己将广告客户字段映射到数据库上的advertiser_id外键,因此最好使用关联映射。您可以在documentation中找到更多信息。

但是,如果由于您自己的原因确实只需要使用一个整数来将advertiser_id存储为整数,则应使用Symfony的数据转换器将广告客户实体转换为如下所示的整数:

$advertiserRepository = $this->advertiserRepository;
$builder->get('advertiser_id')
        ->addModelTransformer(new CallbackTransformer(
            function ($advertiserAsInteger) use ($advertiserRepository) {
                // transform the integer to an entity object
                return $advertiserRepository->find($advertiserAsInteger);
            },
            function ($advertiserAsEntity) {
                // transform the entity back to an integer
                return $advertiserAsEntity->getId();
            }
        ))
    ;

在上面的代码中,我使用了CallbackTransformer来实现转换,但是您也可以使用转换器类来实现。您还可以在data transformers documentation中找到有关此内容的更多信息。

答案 1 :(得分:0)

我想在@iiirxs的答案的一部分中添加我刚刚根据模型转换器的建议实现的自定义类型。

此类型扩展了内置EntityType,因此在很多情况下,您可以将EntityType替换为EntityReferenceType并映射ID。

如果表单未直接映射到实体(例如,使用命令模式),则因此很有用,因此您更希望使用标识符。

use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\PropertyAccess\PropertyAccess;

class EntityReferenceType extends AbstractType
{
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'id_property' => 'id'
        ]);
    }

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder->addModelTransformer(
            new CallbackTransformer(
                function ($entityIdentifier) use ($options) {
                    if ($entityIdentifier === null) {
                        return null;
                    }
                    return $options['em']->getRepository($options['class'])->find($entityIdentifier);
                },
                function ($entity) use ($options) {
                    if ($entity === null) {
                        return null;
                    }
                    return PropertyAccess::createPropertyAccessor()->getValue($entity, $options['id_property']);
                }
            )
        );
    }


    public function getParent(): string
    {
        return EntityType::class;
    }
}