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()));
}
}