Symfony2:防止数据库中的重复,形式为多对一

时间:2015-12-15 09:28:02

标签: php ajax forms symfony doctrine-orm

我有一个父母表格嵌入到另一个表格学生中,其中包含一个学生家长的数据,其中包含多对一的学生。

当新学生注册时,他的父母在数据库的另一个表中记录。然后,如果一个现有兄弟的新学生需要注册,这意味着父母已经在数据库中注册,应该阻止父母再次在数据库中注册,只能升级。

我被告知这是使用数据转换器解决的,但我不知道如何使用它。如果有人可以帮助我,我会很感激。我在这里留下代码:

StudentType.php

  //...
  ->add('responsible1', new ParentsType(),array('label' => 'Mother'))
  ->add('responsible2', new ParentsType(),array('label'=> 'Father'))

实体父母

     /**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

//National identity document
//we have removed "@UniqueEntity(fields={"NID"}, message="...")" 
//so you can put any NID on the form and then check its existence to insert or not.
/**
 * @var string
 *
 * @ORM\Column(name="NID", type="string", length=10)
 * @Assert\NotBlank()
 */
private $nid;

 //more properties...

 /**
 * @ORM\OneToMany(targetEntity="Student", mappedBy="$responsible1")
 * @ORM\OneToMany(targetEntity="Student", mappedBy="$responsible2")
 */
 private $students;

 //...
 public function addStudent(\Cole\BackendBundle\Entity\Student $students)
{
    $this->students[] = $students;

    return $this;
}

public function removeStudent(\Cole\BackendBundle\Entity\Student $students)
{
    $this->students->removeElement($students);
}

public function getStudents()
{
    return $this->students;
}

实体学生

 //...
 /**
 * @ORM\ManyToOne(targetEntity="Parents", inversedBy="students", cascade={"persist"})
 */
 private $responsible1;

/**
 * @ORM\ManyToOne(targetEntity="Parents", inversedBy="students", cascade={"persist"})
 */
 private $responsible2;

 //...

public function setResponsible1($responsible1)
{
    $this->responsible1 = $responsible1;

    return $this;
}


public function getResponsible1()
{
    return $this->responsible1;
}


public function setResponsible2($responsible2)
{
    $this->responsible2 = $responsible2;

    return $this;
}

public function getResponsible2()
{
    return $this->responsible2;
}

ParentsRepository.php

 class ParentsRepository extends EntityRepository
 {
   public function findResponsible($nid)
   {
    return $this->getEntityManager()->createQuery(
        'SELECT p FROM BackendBundle:Parents p WHERE p.nid=:nid')
    ->setParameter('nid',$nid)
    ->setMaxResults(1)
    ->getOneOrNullResult();
   }
 }

StudentController.php

/**
 * Creates a new Student entity.
 *
 */
public function createAction(Request $request)
{
    $entity = new Student();
    $form = $this->createCreateForm($entity);
    $form->handleRequest($request);

    if ($form->isValid()) {

    $responsible1 = $em->getRepository('BackendBundle:Parents')->findResponsible($entity->getResponsible1()->getNid());
    $responsible2 = $em->getRepository('BackendBundle:Parents')->findResponsible($entity->getResponsible2()->getNid());

   if($responsible1){
         $entity->setResponsible1($responsible1->getId()); 
   }
   if($responsible2){
         $entity->setResponsible2($responsible2->getId()); 
   }
   $entity->getResponsible1()->setUsername($entity->getResponsible1()->getNid());
   $entity->getResponsible2()->setUsername($entity->getResponsible2()->getNid());

   $entity->getResponsible1()->setPassword($entity->getResponsible1()->getNid());
   $entity->getResponsible2()->setPassword($entity->getResponsible2()->getNid());


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


        return $this->redirect($this->generateUrl('student_show', array('id' => $entity->getId())));
    }

    return $this->render('BackendBundle:Student:new.html.twig', array(
        'entity' => $entity,
        'form'   => $form->createView(),
    ));
}

使用上面的代码尝试解决问题,但是它给我带来错误,将数据保存到数据库并且不会让我添加到数据库中,但如果使用以下代码来测试新学生创建并指定父对应的不要再次创建它们(假设您之前已经创建过)。

    $responsible1 = $em->getRepository('BackendBundle:Parents')->findResponsible(4); //The number corresponds to the id of the parent
    $responsible2 = $em->getRepository('BackendBundle:Parents')->findResponsible(5);

    $entity->setResponsible1($responsible1->getId()); 
    $entity->setResponsible2($responsible2->getId()); 

我不知道我在做什么是对的。我读了一些东西,使用Data Transformers或事件监听器作为PrePersist和Preupdate,但我不知道如何使用它。

提前感谢您的回答。

3 个答案:

答案 0 :(得分:1)

而不是

if($responsible1){
     $entity->setResponsible1($responsible1->getId()); 
}
if($responsible2){
     $entity->setResponsible2($responsible2->getId()); 
}
$entity->getResponsible1()->setUsername($entity->getResponsible1()->getNid());
$entity->getResponsible2()->setUsername($entity->getResponsible2()->getNid());

$entity->getResponsible1()->setPassword($entity->getResponsible1()->getNid());
$entity->getResponsible2()->setPassword($entity->getResponsible2()->getNid());

你可以写

if($responsible1){
     $entity->setResponsible1($responsible1); 
}
if($responsible2){
     $entity->setResponsible2($responsible2); 
}

它应该有用。

但我认为更好的解决方案是为FormEvents::SUBMIT事件添加事件监听器。此事件允许您从表单数据的规范化表示中更改数据。所以你需要做的就是这样:

public function onSubmit(FormEvent $event)
{
   $student = $event->getData();

   if ($student->getResponsible1()) {
        $parentNid = $student->getResponsible1()->getNid();

        // here you check the database to see if you have a parent with this nid
        // if a parent exists, replace the current submitted parent data with the parent entity existing in your db
   }

希望这会有所帮助。如果我需要提供更多细节,请告诉我。

答案 1 :(得分:1)

这里是我的想法,从评论中,你说你正在使用国家身份证明文件(希望它是一个整数表示),将它作为父表的主键并使这个独特的,所以当第二个学生是另一个学生的兄弟姐妹时输入相同的细节并提交,数据库将抛出错误,处理该错误并继续

编辑:甚至可能不需要将国家身份作为主键,只是让它成为唯一的,不管怎样你应该这样做,你错过了这个。

当学生输入国家身份时,您可以使用symfony实体表单类型加载(ajax)父实体

答案 2 :(得分:0)

根据您的关系判断,您希望避免将同一个学生两次添加到Parents实体。有一个简单的技巧,ArrayCollaction类有一个名为contains的方法,如果已在集合中找到值或对象,则返回true。更好in_array

因此,如果$parent已包含即将添加的$student并采取相应措施,则需要在加法器内部进行检查。如下所示:

public function addStudent(\Cole\BackendBundle\Entity\Student $student)
{
    if (!$this->students->contains($student)) {
        $this->students[] = $students;
    }    

    return $this;
}