dpsfay2510 2014-06-14 05:52
浏览 45
已采纳

Symfony2注册表单只有单一的收集记录字段

So I'm trying to create a registration form in Symfony 2 which contains my "Person" entity. The person entity has a one-to-many join, and I want the registration form to allow the user to select a single instance of this "Many" side of the join.

The structure is Users and Institutions. A user can have many institutions. I want a user to select a single institution at registration time (but the model allows for more later).

The basic structure is:

RegistrationType -> PersonType -> PersonInstitutionType

…with corresponding models:

Registration (simple model) -> Person (doctrine entity) -> PersonInstitution (doctrine entity, oneToMany relation from Person)

I tried to pre-populate an empty Person & PersonInstitution record in the RegistrationController but it gives me the error:

Expected argument of type "string or Symfony\Component\Form\FormTypeInterface", "TB\CtoBundle\Entity\PersonInstitution" given

(ok above has been fixed).

I've moved the code from my website to here below, trying to remove all the irrelevant bits.

src/TB/CtoBundle/Form/Model/Registration.php

namespace TB\CtoBundle\Form\Model;
use TB\CtoBundle\Entity\Person;
class Registration 
{
  /**
   * @var Person
   */
  private $person
  private $termsAccepted;
}

src/TB/CtoBundle/Form/RegistrationType.php

namespace TB\CtoBundle\Form;
use TB\CtoBundle\Form\PersonType;
class RegistrationType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('person',  new PersonType());
        $builder->add('termsAccepted','checkbox');
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'TB\CtoBundle\Form\Model\Registration',
            'cascade_validation' => true,
        ));
    }
    public function getName()
    {
        return 'registration';
    }
}

src/TB/CtoBundle/Entity/Person.php

namespace TB\CtoBundle\Entity;
use TB\CtoBundle\Entity\PersonInstitution
/**
 * @ORM\Entity()
 */
class Person
{
    /**
     * @var ArrayCollection
     * @ORM\OneToMany(targetEntity="PersonInstitution", mappedBy="person", cascade={"persist"})
     */
    private $institutions;
}

src/TB/CtoBundle/Form/PersonType.php

namespace TB\CtoBundle\Form;
class PersonType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $builder
            ->add('institutions', 'collection', array('type' => new PersonInstitutionType()))
        ;
    }

   /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'TB\CtoBundle\Entity\Person',
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'tb_ctobundle_person';
    }
}

src/TB/CtoBundle/Entity/PersonInstitution.php

namespace TB\CtoBundle\Entity
/**
 * PersonInstitution
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class PersonInstitution
{
    /**
     * @ORM\ManyToOne(targetEntity="Person", inversedBy="institutions", cascade={"persist"})
     */
    private $person;

    /**
     * @ORM\ManyToOne(targetEntity="Institution", inversedBy="members")
     */
    private $institution;

    /**
     * @ORM\Column(type="boolean")
     */
    private $approved;
}

src/TB/CtoBundle/Form/PersonInstititionType.php

namespace TB\CtoBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class PersonInstitutionType extends AbstractType
{
        /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('approved')
            ->add('person')
            ->add('institution')
        ;
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'TB\CtoBundle\Entity\PersonInstitution'
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'tb_ctobundle_personinstitution';
    }
}

src/TB/CtoBundle/Controller/Registration.php

namespace TB\CtoBundle\Controller;
class RegisterController extends Controller
{

    /**
     * 
     * @param Request $request
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
     */
    public function registerAction(Request $request)
    {
        $registration = new Registration;

        $person = new Person();
        $institution = new PersonInstitution();
        $person->addInstitution($institution);
        $registration->setPerson($person);

// this causes error:
// Entities passed to the choice field must be managed. Maybe persist them in the entity manager? 
//        $institution->setPerson($person);

        $form = $this->createForm(new RegistrationType(), $registration);

        $form->handleRequest($request);

        if($form->isValid()) {
            $registration = $form->getData();
            $person = $registration->getPerson();

            // new registration - account status is "pending" 
            $person->setAccountStatus("P");

            // I'd like to get rid of this if possible
            // for each "PersonInstitution" record, set the 'person' value
            foreach($person->getInstitutions() as $rec) {
                $rec->setPerson($person);
            }

            $em = $this->getDoctrine()->getManager();
            $em->persist($person);
            $em->flush();
        }

        return $this->render('TBCtoBundle:Register:register.html.twig', array('form' => $form->createView()));
    }
}
  • 写回答

1条回答 默认 最新

  • drnpwmq4536 2014-06-14 08:52
    关注

    Here is a detailed solution for adding an Collection field to Person entity and formType. Your complex question with Registration entity can be solved with this. I suggest you to use this 3 entity related connection if it is really needed. (only because of termsAccepted data!?)

    If you won't change your opinion, then use this annotation: Registration code:

    use TB\CtoBundle\Entity\Person;
    /**
      * @ORM\OneToOne(targetEntity="Person")
      * @var Person
      */
    protected $person;
    

    Person code:

    use TB\CtoBundle\Entity\PersonInstitution;
    
    /**
      * @ORM\OneToMany(targetEntity="PersonInstitution", mappedBy = "person")
      * @var ArrayCollection
      */
    private $institutions;
    
    /* I suggest you to define these functions:
    setInstitutions(ArrayCollection $institutions),
    getInstitutions()
    addInstitution(PersonInstitution $institution)
    removeInstitution(PersonInstitution $institution)
    */
    

    PersonInstitution code:

    use TB\CtoBundle\Entity\Person;
    
    /**
      * @ORM\ManyToOne(targetEntity="Person", inversedBy="institutions", cascade={"persist"}))
      * @var Person
      */
    private $person;
    

    PersonType code:

    use TB\CtoBundle\Form\PersonInstitutionType;
    
    ->add('institutions', 'collection', array(
                    'type' => new PersonInstitutionType(), // here is your mistake!
                    // Other options can be selected here.
                    //'allow_add' => TRUE,
                    //'allow_delete' => TRUE,
                    //'prototype' => TRUE,
                    //'by_reference' => FALSE,
    ));
    

    PersonController code:

    use TB\CtoBundle\Entity\Person;
    use TB\CtoBundle\Entity\PersonInstitution;
    
    /**
      * ...
      */
    public funtcion newAction()
    {
      $person = new Person;
      $institution = new PersonInstitution;
      $institution->setPerson($person);
      $person->addInstitution($institution);
      $form = $this->createForm(new PersonType($), $person); // you can use formFactory too.
    
      // If institution field is required, then you have to check,
      // that is there any institution able to chose in the form by the user.
      // Might you can redirect to institution newAction in that case.
    
      return array( '...' => $others, 'form' => $form);
    }
    

    If you need more help in twig code, then ask for it.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图