Symfony3 FOS User下UsersType注入EntityType表单提交类型错误如何解决
修复方案
方案1:使用数据转换器(推荐,适用中间表有自定义字段的场景)
如果你的UsersChannelBrand中间表除了关联用户和品牌外还有其他字段,用数据转换器做类型转换即可:
- 新建数据转换器类
// src/Bl/CoreBundle/Form/DataTransformer/ChannelBrandToUsersChannelBrandTransformer.php namespace Bl\CoreBundle\Form\DataTransformer; use Bl\CoreBundle\Entity\ChannelBrand; use Bl\CoreBundle\Entity\UsersChannelBrand; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\DataTransformerInterface; class ChannelBrandToUsersChannelBrandTransformer implements DataTransformerInterface { private $em; private $currentUser; public function __construct(EntityManagerInterface $em, $currentUser) { $this->em = $em; $this->currentUser = $currentUser; } // 表单渲染:把UsersChannelBrand转换为ChannelBrand供前端选择展示 public function transform($usersChannelBrands) { if (null === $usersChannelBrands) return new ArrayCollection(); $channelBrands = new ArrayCollection(); foreach ($usersChannelBrands as $ucb) { $channelBrands->add($ucb->getChannelbrand()); } return $channelBrands; } // 表单提交:把选中的ChannelBrand转换为UsersChannelBrand关联实例 public function reverseTransform($channelBrands) { $usersChannelBrands = new ArrayCollection(); foreach ($channelBrands as $cb) { // 避免重复创建已有的关联 $existing = $this->em->getRepository(UsersChannelBrand::class) ->findOneBy(['users' => $this->currentUser, 'channelbrand' => $cb]); if ($existing) { $usersChannelBrands->add($existing); continue; } // 创建新的关联实例 $ucb = new UsersChannelBrand(); $ucb->setUsers($this->currentUser); $ucb->setChannelbrand($cb); // 中间表有其他字段可在这里赋值 $usersChannelBrands->add($ucb); } return $usersChannelBrands; } }
- 修改
UsersType注入EntityManager并绑定转换器
use Bl\CoreBundle\Form\DataTransformer\ChannelBrandToUsersChannelBrandTransformer; use Doctrine\ORM\EntityManagerInterface; class UsersType extends AbstractType { private $em; // 注入EntityManager public function __construct(EntityManagerInterface $em) { $this->em = $em; } public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('email', EmailType::class, array('label' => 'Email')) ->add('username', TextType::class, array('label' => 'Usuario')) ->add('name', TextType::class, array('label' => 'Nombre')) ->add('lastname', TextType::class, array('label' => 'Apellido')) ->add('roles', CollectionType::class, array('label' => 'Roles')) ->add('channelbrand_isolation', CheckboxType::class, array('label' => 'Aislado', 'required' => false)) ->add('userschannelbrand', EntityType::class, array( 'class' => 'Bl\CoreBundle\Entity\ChannelBrand', 'query_builder' => function (EntityRepository $er) { return $er->createQueryBuilder('cb') ->where('cb.isActive =:active')->setParameter('active', true) ->orderBy('cb.name', 'ASC'); }, 'choice_label' => 'name', 'multiple' => true, 'label' => 'Canal', 'required' => false, )) ->add('enabled', CheckboxType::class, array('label' => 'Activo', 'required' => false)) ; // 给userschannelbrand字段绑定转换器 $builder->get('userschannelbrand') ->addModelTransformer(new ChannelBrandToUsersChannelBrandTransformer( $this->em, $options['data'] // 当前编辑的用户实例 )); } // 剩余原有代码保持不变 }
- 把
UsersType注册为服务(Symfony3.3+开启自动配置可省略)
方案2:直接改为多对多关联(适用中间表无额外字段的场景)
如果你的UsersChannelBrand中间表只有用户ID和品牌ID两个关联字段,没有其他自定义字段,可以直接把关联改为多对多,不需要中间实体,表单不用任何修改即可正常使用:
// 替换Users实体里原有userschannelbrand的关联注解 /** * @ORM\ManyToMany(targetEntity="Bl\CoreBundle\Entity\ChannelBrand") * @ORM\JoinTable(name="users_channel_brand", // 填写你原有中间表的表名 * joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}, * inverseJoinColumns={@ORM\JoinColumn(name="channel_brand_id", referencedColumnName="id")} * ) */ protected $userschannelbrand;
改完执行php bin/console doctrine:schema:update --force更新数据库即可。
内容的提问来源于stack exchange,提问作者Luciano
相关产品推荐
相关产品推荐

