2013-06-03 9 views
3

У меня есть следующие объекты:Как узнать, что отношение OneToMany было изменено?

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

    /** 
    * 
    * @ORM\OneToMany(targetEntity="PersonEmail", mappedBy="person", cascade={"persist", "remove"}) 
    */ 
    private $emails; 

    /** 
    * @var datetime $updated 
    * 
    * @ORM\Column(type="datetime") 
    */ 
    private $updated; 
} 

.

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

    /** 
    * @var string 
    * 
    * @ORM\Column(name="email", type="string", length=255) 
    */ 
    private $email; 

    /** 
    * @ORM\ManyToOne(targetEntity="Person", inversedBy="emails") 
    * @ORM\JoinColumn(name="person_id", referencedColumnName="id", onDelete="CASCADE") 
    */ 
    private $person; 
} 

Я использую конструктор форм Symfony2 для создания форм. После отправки формы я звоню $form->bind($request). И мой вопрос: как узнать, что электронные письма были изменены (вставлены, обновлены или удалены), прежде чем я сохраню объект Person? Мне нужно это, потому что я хочу обновить поле Person :: $ updated. Я могу сделать это, когда объект Person изменен сам с помощью обратного вызова жизненного цикла PreUpdate, но как я могу обновить это поле, когда был изменен только список адресов электронной почты? Прогнозирование самого легкого ответа: я бы хотел избежать обновления этого поля, когда ничего не изменилось вообще.

Обновление объекта Person в обратном вызове PersonEmail невозможен, поскольку объект Person уже обработан в этот момент.

код контроллера (не уверен, если это поможет):

/** 
* 
* @Template() 
*/ 
public function editAction($id, Request $request) 
{ 
    $repository = $this->getDoctrine()->getRepository('AcmeBundle:Person'); 
    $person = $repository->find($id); 
    if (!$person) { 
     throw $this->createNotFoundException('No person found for id '.$id); 
    } 
    if ($request->isMethod('POST')) { 
     $form->bind($request); 
     if ($form->isValid()) { 
      $em = $this->getDoctrine()->getEntityManager(); 
      $em->flush(); 
     } 
    } 
    return array('form' => $form->createView(), 'person' => $person); 
} 
+0

Можете ли вы опубликовать код своего контроллера? – cheesemacfly

+0

@cheesemacfly: Я обновил вопрос –

+0

Почему бы вам в вашем контроллере не проверить, что '$ originalperson-> emails === $ person-> emails' после' $ form-> bind ($ request) ', а если нет, просто вызовите '$ person-> updated = new \ DateTime()'? – cheesemacfly

ответ

0

Вот мое решение. Это не так элегантно, как я надеялся получить, но в любом случае, по крайней мере, это работает. Таким образом, в моем решении мы сначала проверяем, грязная ли коллекция электронных писем (что означает, что некоторые электронные письма были добавлены и/или удалены). Если это не грязно, нам все равно нужно проверить, не были ли сделаны какие-либо изменения в существующих письмах. Я надеялся использовать для этого какой-то существующий API, но, похоже, для этого случая нет ни одного из них. Итак, я решил вручную проверить свои данные для изменений. Пример кода.

/** 
* 
* @Template() 
*/ 
public function editAction($id, Request $request) 
{ 
    $repository = $this->getDoctrine()->getRepository('AcmeBundle:Person'); 
    $person = $repository->find($id); 
    if (!$person) { 
     throw $this->createNotFoundException('No person found for id '.$id); 
    } 
    if ($request->isMethod('POST')) { 
     $form->bind($request); 
     if ($form->isValid()) { 
      $em = $this->getDoctrine()->getEntityManager(); 

      // isDirty() will be true if emails were added or deleted 
      if ($person->getEmails()->isDirty()) { 
       $person->setUpdated(new \DateTime(date('Y-m-d H:i:s'))); 
      } else { 
       $uow = $em->getUnitOfWork(); 

       // as no one suggested a working solution, I just decided 
       // to check entity by entity, field by field 
       // if anything is changed, we'll mark $person as updated 
       foreach($person->getEmails() as $item) { 
        $orig = $uow->getOriginalEntityData($item); 
        if ($item->getEmail() != $orig['email']) { 
         $person->setUpdated(new \DateTime(date('Y-m-d H:i:s'))); 
         break; 
        } 
       } 
      } 
      $em->flush(); 
     } 
    } 
    return array('form' => $form->createView(), 'person' => $person); 
} 

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

Смежные вопросы