2015-05-26 1 views
3

У меня есть проблема с сохранением сущности с помощью отношений ManyToMany.Форма Symfony не сохраняет объект с отношением ManyToMany

Я не могу сохранить поля, которые находятся на стороне «mappedBy».

Код ниже не спасает ничего к базе данных и не trowing ошибки:

// Entity/Pet 
/** 
* @var \Doctrine\Common\Collections\Collection 
* 
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Customer", mappedBy="pet", cascade={"persist"}) 
*/ 
private $customer; 

/** 
* Set customer 
* 
* @param \AppBundle\Entity\Customer $customer 
* @return Pet 
*/ 
public function setCustomer($customer) 
{ 
    $this->customer = $customer; 

    return $this; 
} 

// Entity/Customer 
/** 
* @var Pet 
* 
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Pet", inversedBy="customer", cascade={"persist"}) 
* @ORM\JoinTable(name="customer_pet", 
* joinColumns={ 
*  @ORM\JoinColumn(name="customer_id", referencedColumnName="id") 
* }, 
* inverseJoinColumns={ 
*  @ORM\JoinColumn(name="pet_id", referencedColumnName="id") 
* } 
*) 
*/ 
private $pet; 

// PetType.php 
$builder->add('customer', 'entity', 
      array(
      'class' => 'AppBundle:Customer', 
      'property' => 'firstname', 
      'empty_value' => 'Choose owner', 
      'multiple' => true 
     )); 

Она работает наоборот. Поэтому, если я что-то сохраняю из CustomerType, все работает.

EDIT:

Решение ниже работал для меня, но после нескольких дней я обнаружил проблему с этим решением. Если форма будет отправлена ​​со значением, которое уже было сохранено в базе данных, тогда Symfony вытолкнет ошибку. Чтобы предотвратить, что я должен был проверить, был ли данный клиент уже назначен домашнему животному.

Проверка назначенных клиентов должна выполняться в начале функции, а не после отправки формы, поскольку по какой-либо причине после представления объекта Pet() представлены представленные значения не только те, что присутствуют в db.

Так в начале я гнал все уже присвоенные клиентов к массиву

$em = $this->getDoctrine()->getManager(); 
    $pet = $em->getRepository('AppBundle:Pet')->find($id); 
    $petOriginalOwners = array(); 
    foreach ($pet->getCustomer() as $petCustomer) 
    { 
     $petOriginalOwners[] = $petCustomer->getId(); 
    } 

И после отправки формы я проверил, если представленные идентификаторы в массиве

if ($form->isValid()) 
{ 
    foreach ($form['customer']->getData()->getValues() as $v) 
    { 
    $customer = $em->getRepository('AppBundle:Customer')->find($v->getId()); 
    if ($customer && !in_array($v->getId(), $petOriginalOwners))  
    { 
     $customer->addPet($pet); 
    } 
    } 
    $em->persist($pet); 
    $em->flush(); 
    return $this->redirect($this->generateUrl('path')); 
} 

ответ

1

В Symfony2 объект с свойством с комментарием inversedBy доктрины - это тот, который должен ИЗМЕНИТЬ ДОПОЛНИТЕЛЬНЫЙ ТАБЛИЦ, СОЗДАННЫЙ ОТНОШЕНИЕМ MANYTOMANY. Вот почему при создании клиента он вставляет соответствующие строки в эту дополнительную таблицу, сохраняя соответствующих домашних животных.

Если вы хотите такое же поведение произойдет наоборот, я рекомендую:

//PetController.php 
public function createAction(Request $request) { 
    $entity = new Pet(); 
    $form = $this->createCreateForm($entity); 
    $form->submit($request); 



    if ($form->isValid()) { 
     $em = $this->getDoctrine()->getManager(); 
     foreach ($form['customer']->getData()->getValues() as $v) { 
      $customer = $em->getRepository('AppBundle:Customer')->find($v->getId()); 
      if ($customer) { 
       $customer->addPet($entity); 
      } 
     } 
     $em->persist($entity); 
     $em->flush(); 

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

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

private function createCreateForm(Pet $entity) { 
     $form = $this->createForm(new PetType(), $entity, array(
      'action' => $this->generateUrl('pet_create'), 
      'method' => 'POST', 
     )); 

     return $form; 
    } 

Эти два являются стандартными, но Symfony2 CRUD сгенерированные действия в контроллере, соответствующего Pet лица.

Единственная настройка - foreach структура, вставленная в первое действие, таким образом вы принудительно добавляете одно и то же домашнее животное каждому клиенту, который вы выбираете в форме, тем самым получаете желаемое поведение.

Посмотрите, это очень вероятно. Это не ПРАВОЙ ПУТЬ, или ПРАВИЛЬНЫЙ ПУТЬ, но ПУТЬ, и это работает. Надеюсь, поможет.

+0

Спасибо, что работает, я не думаю, что в этом решении есть что-то не так, это просто. Если он работает и не добавляет каких-либо уязвимостей в систему, то ЭТО - ПРАВИЛЬНЫЙ ПУТЬ. Еще раз спасибо! – Draco