#php #mysql #doctrine-orm
#php #mysql #doctrine-orm
Вопрос:
У меня есть две сущности — Пользователи и проблемы. Пользователь может участвовать во многих задачах, а в задаче может быть много участников (пользователей). Я начал подходить к этой проблеме, создав отношение многие-ко-многим в моем классе Users:
/**
* @ORMManytoMany(targetEntity="Challenge")
* @ORMJoinTable(name="users_challenges",joinColumns={@ORMJoinColumn(name="user_id",referencedColumnName="id")},
* inverseJoinColumns={@ORMJoinColumn(name="challenge_id",referencedColumnName="id")})
*
*/
protected $challenges;
Однако затем я понял, что мне нужно сохранить атрибут расстояния для комбинации пользователь / вызов (как далеко пользователь продвинулся в своем вызове). В документах Doctrine2 указано:
«Почему ассоциации многие-ко-многим встречаются реже? Поскольку часто требуется связать дополнительные атрибуты с ассоциацией, в этом случае вы вводите класс ассоциации. Следовательно, прямая связь многие-ко-многим исчезает и заменяется ассоциациями один-ко-многим / многие-к-одному между 3 участвующими классами «.
Итак, мой вопрос в том, какими должны быть эти ассоциации между User, Challenge и UsersChallenges?
Обновить
Ссылки на код сущности см. В комментарии к первому ответу. У меня есть метод контроллера ниже, который всегда создает новую запись UsersChallenges, а не обновляет существующую (чего я и хочу)
public function updateUserDistanceAction()
{
$request = $this->getRequest();
$distance = $request->get('distance');
$challenge_id = $request->get('challenge_id');
if($request->isXmlHttpRequest()) {
$em = $this->getDoctrine()->getEntityManager();
$user = $this->get('security.context')->getToken()->getUser();
$existingChallenges = $user->getChallenges();
$challengeToUpdate = $em->getRepository('GymloopCoreBundle:Challenge')
->find( (int) $challenge_id);
if(!$challengeToUpdate) {
throw $this->createNotFoundException('No challenge found');
}
//does the challengeToUpdate exist in existingChallenges? If yes, update UsersChallenges with the distance
//if not, create a new USersChallenges object, set distance and flush
if ( !$existingChallenges->isEmpty() amp;amp; $existingChallenges->contains($challengeToUpdate)) {
$userChallenge = $em->getRepository('GymloopCoreBundle:UsersChallenges')
->findOneByChallengeId($challengeToUpdate->getId());
$userChallenge->setDistance( $userChallenge->getDistance() (int) $distance );
$em->flush();
} else {
$newUserChallenge = new UsersChallenges();
$newUserChallenge->setDistance($distance);
$newUserChallenge->setChallenge($challengeToUpdate);
$newUserChallenge->setUser($user);
$user->addUsersChallenges($newUserChallenge);
$em->persist($user);
$em->persist($newUserChallenge);
$em->flush();
}
//if success
return new Response('success');
//else
}
}
Ответ №1:
Пользователь (один-ко-многим) -> Пользовательские вызовы
Пользовательские вызовы (многие-к-одному) -> Пользователь
Пользовательские вызовы (многие-к-одному) -> Вызов
Вызов (один ко многим) -> Пользовательские вызовы
Комментарии:
1. Спасибо. Для вас это нормально? gist.github.com/1280574 , gist.github.com/1280576 , gist.github.com/1280579
Ответ №2:
я полагаю, вы хотите $em->persist($userChallenge);
, чтобы перед $em->flush();
$userChallenge->setDistance( $userChallenge->getDistance() (int) $distance );
$em->persist($userChallenge);
$em->flush();
Однако я не уверен, решает ли это вашу проблему.
Можете ли вы публиковать isEmpty
и contains
функционировать в existingChallenges
Ответ №3:
Этот код сработал. Одна из проблем заключалась в том, что я проверял, содержит ли коллекция UserChallenge объект вызова, который, очевидно, потерпит неудачу.
Рабочий код:
if ( !$existingChallenges->isEmpty() ) {
foreach($existingChallenges as $ec) {
$existingChallengeIdArray[] = $ec->getId();
}
}
if( in_array($challenge_id, $existingChallengeIdArray) ) {
$userChallenge = $em->getRepository('GymloopCoreBundle:UsersChallenges')
->findOneByChallenge($challengeToUpdate->getId());
$userChallenge->setDistance( $userChallenge->getDistance() (int) $distance );
$em->flush();
} else {
$newUserChallenge = new UsersChallenges();
$newUserChallenge->setDistance($distance);
$newUserChallenge->setChallenge($challengeToUpdate);
$newUserChallenge->setUser($user);
$user->addUsersChallenges($newUserChallenge);
$em->persist($newUserChallenge);
$em->flush();
}