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

时间:2014-06-14 05:52:18

标签: php forms symfony doctrine-orm

所以我试图在Symfony 2中创建一个包含我的“Person”实体的注册表单。人员实体具有一对多联接,我希望注册表单允许用户选择联接的“多个”一侧的单个实例。

结构为UsersInstitutions。用户可以拥有许多机构。我希望用户在注册时选择一个机构(但模型允许以后更多)。

基本结构是:

  

RegistrationType - > PersonType - > PersonInstitutionType

...与相应的型号:

  

注册(简单模型) - >人(学说实体) - > PersonInstitution(学说实体,来自Person的oneToMany关系)

我试图预先填充空Person& PersonInstitution中的RegistrationController记录,但它给出了错误:

  

“String或Symfony \ Component \ Form \ FormTypeInterface”,“TB \ CtoBundle \ Entity \ PersonInstitution”类型的预期参数

(上面确定已修复)。

我已将代码从我的网站移到此处,尝试删除所有无关的位。

的src / TB / CtoBundle /窗体/型号/和registration.php

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

的src / TB / CtoBundle /窗体/ 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 /实体/ 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 /窗体/ 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 /实体/ 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 /窗体/ 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 /控制器/和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 个答案:

答案 0 :(得分:1)

以下是向Person实体和formType添加Collection字段的详细解决方案。 您可以通过此解决注册实体的复杂问题。 如果确实需要,我建议你使用这个与实体相关的3连接。 (仅因为术语接受数据!?)

如果您不会改变您的意见,请使用此注释: 注册码

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

人员代码

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代码

use TB\CtoBundle\Entity\Person;

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

PersonType代码

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代码

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

如果您在twig代码中需要更多帮助,请提出要求。