【问题标题】:Symfony Form to store a selection of User Interests to UserInterestsSymfony 表单将用户兴趣的选择存储到 UserInterests
【发布时间】:2019-07-04 08:59:02
【问题描述】:

我的目标是使用 Symfony 表单来允许用户选择多个兴趣并将这些与他们的用户相关地保存。

我有三个实体来映射和存储这些数据:

User
 - id
 - name

Interest
 - id
 - name

UserInterest
 - id
 - user_id (FK ManyToOne user.id)
 - interest_id (FK ManyToOne interest.id)

我正在努力寻找最动态的 Symfony 方法来处理 UserInterests 并将其保存到 UserInterest 实体。

InterestsController.php

public function interests(Request $request)
{
    $error = null;

    $userInterests = new UserInterest();
    $userInterests->setUser($this->getUser());

    $form = $this->createForm(UserAccountInterests::class, $userInterests);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        try {
            $this->entityManager->persist($userInterests);
            $this->entityManager->flush();
    } catch (\Exception $e) {
            $error = $e->getMessage();
        }
    }

    $parameters = [
        'error' => $error,
        'user_interests_form' => $form->createView()
    ];

    return $this->render('user/interests.html.twig', $parameters);
}

UserInterestsType.php

class UserInterestsType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
    $builder
        ->add('interest', EntityType::class, [
            'class' => Interest::class,
            'choice_label' => 'name',
            'expanded' => true,
            'multiple' => true
        ])
        ->add('update', SubmitType::class);
    }
 }

问题

我目前面临的问题是,在提交表单时,这会创建一个链接到userUserInterest 实体的实例化,但将多个选定的Interest 作为数组而不是多个UserInterest

我怎样才能以正确的 Symfony 方式执行此操作,以允许一个表单和简单的控制器逻辑,以便用户可以加载页面,从多个复选框类型中选择他们的兴趣,单击保存,然后当重新加载表单时它们是自动填充为先前的选择?

【问题讨论】:

标签: php symfony symfony4 symfony-forms


【解决方案1】:

您的第一个解决方案对于您想要实现的目标来说有点过于复杂。如果您只想让用户选择一些兴趣,则不需要 UserInterest 实体。

对于专门用于该关系的新实体,我能想到的唯一用途是该关系是否带有一些您想要保留的额外属性,例如关系开始的日期,可能是订单或优先级或您需要的任何东西。如果您要存储的唯一数据是 userId 和 interestId,那么新实体不会给您带来太多,而是复杂性。 您也不需要 CollectionType(无论如何您都不会在此表单上产生新的兴趣)。在用户和兴趣之间建立一个简单的多对多关系

 User:
  type: entity
  manyToMany:
    interests:
      targetEntity: Interest
      inversedBy: users
      joinTable: 
        ## name will be the name of the table storing your entities 's relations
        ## Beware not to give it a name already defined for an entity table (like your UserInterest wich you don't need anymore)
        name: users_interests 
        joinColumns:
          user_id:
            referencedColumnName: id
        inverseJoinColumns:
          interest_id:
            referencedColumnName: id

Interest:
  type: entity
  manyToMany:
    users:
      targetEntity: User
      mappedBy: interests

然后您可以在 data_class 是 User 并且您的 entitytype 的类是 Interest 的表单中使用简单的多个 EntityType:

class UserInterestsType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
    $builder
        ->add('interests', EntityType::class, [
            'class' => Interest::class,
            'choice_label' => 'name',
            'expanded' => true,
            'multiple' => true,
            'query_builder' => function (EntityRepository $er) {
    return $er->createQueryBuilder('u')
        ->orderBy('u.name', 'ASC');
}, 
        ])
        ->add('update', SubmitType::class);
    }
 }

然后假设您要检索共享特定兴趣的用户或特定用户的兴趣,您将在现有的用户和兴趣存储库中进行此类查询:

// UserRepository: All users sharing one (or more) interests
$em = $this->getEntityManager();
$repository = $em->getRepository('YourNamespace:User');
$query = $repository->createQueryBuilder('u')
    ->innerJoin('u.interests', 'i')
    ->where('i.id = :interest_id')
    ->setParameter('interest_id', 5) // just for the example
    ->getQuery()->getResult();

// InterestRepository: All interests of one user 
$em = $this->getEntityManager();
$repository = $em->getRepository('YourNamespaceYourBundle:Interest');
$query = $repository->createQueryBuilder('i')
    ->innerJoin('i.users', 'u')
    ->where('u.id = :user_id')
    ->setParameter('user_id', 1)
    ->getQuery()->getResult();

【讨论】:

  • 这很接近但我得到了:The table with name 'table.user_interest' already exists.
  • 好的,你删除了你的实体 UserInterest 吗?或者确保您之前创建的实体 UserInterest 最终不会创建 user_interest 表?
  • 但是我有一个user_interesest 表,关系存储在哪里?每个用户与他们相关的兴趣。
  • 是的,但是这个表现在是由多对多关系生成的,您可以通过 joinTable->name 参数在 YAML 文件中指定名称(我编辑了我的回复)。问题是,如果你保留你的 UserInterest 实体,她可能会生成一个他自己的 user_interest(s) 表
  • 完美,这行得通!如果我想查询生成的新表,我应该使用自定义查询而不是实体管理器吗?
猜你喜欢
  • 2015-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-18
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多