Joseph
Joseph

Reputation: 859

Symfony2: Prevent duplicate in database with form Many to One

I have a Parents form embedded into another form Student containing the data of the parents of a student with an association of Many to one.

When a new student registration are recorded his parents in another table in the database. Then if a new student who is brother of an existing need to register, meaning that parents are already registered in the database, should be prevented from parents to register again in the database, could only upgrade .

I'm told that this is solved using data transformers, but I do not know how to use it. If someone could help me I would appreciate it. Here I leave the code:

StudentType.php

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

Entity Parents

     /**
 * @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;
}

Entity Student

 //...
 /**
 * @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(),
    ));
}

With the above code attempts to solve the problem but it gives me error to persist data to the database and will not let me add to the database, but if you use the following code to test the new student creates and assigns parents corresponding not create them again (assuming you were already created earlier).

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

I do not know if what I'm doing is right.I read something to use Data Transformers or event listener as PrePersist and Preupdate, but I don't know how to use this.

Thanks in advance for your answers.

Upvotes: 3

Views: 1901

Answers (3)

some_groceries
some_groceries

Reputation: 1192

Here's my thoughts, from the comments, you said you are using a national identity document(hopefull its an integer representation), make this the primary key of the parent table and make this unique, so when the second student who is the sibling of a another student enters the same details and submits, the database will throw an error, handle that error and continue on

edit: it may not even be required to make the national identity the primary key, just make it unique, you were supposed to do this regardless, you missed this one.

you can use symfony entity form type to load (ajax) the parent entity when the student enters the national identity

Upvotes: 1

Alexandru Furculita
Alexandru Furculita

Reputation: 1373

Instead of

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

you can write

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

And it should work.


But I think a better solution will be to add an event listener to the FormEvents::SUBMIT event. This event allows you to change data from the normalized representation of the form data. So all you need to do is something like this:

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
   }

Hope this helps. Let me know if I have to give more details.

Upvotes: 1

stevenll
stevenll

Reputation: 1025

Judging from your relationship, you want to avoid that the same student is added twice to the Parents entity. There is a simple trick for that, ArrayCollaction class has a method named contains it returns true if a value or object is already found in the collection. A better in_array.

So, you need to check inside the adder if the $parent already contains the $student that is about to be added and act accordingly. Like shown below:

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

    return $this;
}

Upvotes: 1

Related Questions