Symfony2: Предотвращение дублирования в базе данных с формой от многих до одного

У меня есть форма родителя, встроенная в другую форму Студент, содержащий данные родителей ученика с ассоциацией «Множество к одному».

Когда новая регистрация ученика записывается его родителями в другую таблицу в базе данных. Затем, если новый студент, который является братом существующей потребности в регистрации, то есть, что родители уже зарегистрированы в базе данных, следует помешать родителям снова зарегистрироваться в базе данных, может только обновиться.

Мне говорят, что это решается с помощью трансформаторов данных, но я не знаю, как его использовать. Если бы кто-то мог мне помочь, я был бы признателен. Здесь я оставляю код:

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; } -  /** * @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, но я не знаю, как это использовать.

Заранее благодарю за ваши ответы.

Related of "Symfony2: Предотвращение дублирования в базе данных с формой от многих до одного"

Вместо

 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 } 

Надеюсь это поможет. Дайте мне знать, если я должен дать более подробную информацию.

Вот мои мысли , из комментариев вы сказали, что используете национальный документ, удостоверяющий личность (надеюсь, его целочисленное представление), сделайте это первичным ключом родительской таблицы и сделайте это уникальным, поэтому, когда второй студент, являющийся родственником другой студент вводит одни и те же данные и отправляет, база данных будет вызывать ошибку, обрабатывать эту ошибку и продолжать

edit: возможно, даже не требуется, чтобы национальная идентичность была основным ключом, просто сделайте ее уникальной, вы должны были делать это независимо от того, вы пропустили это.

вы можете использовать тип формы объекта symfony для загрузки (ajax) родительского объекта, когда студент вводит национальную идентификацию

Судя по вашим отношениям, вы хотите избежать того, чтобы один и тот же ученик дважды добавлялся к сущности 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; }