В моем проекте Symdony2 у меня есть две взаимосвязанные сущности: Service и ServiceGroup.Это должно быть отношение «многие ко многим», потому что каждая группа может иметь много услуг, и каждая услуга может принадлежать многим группам.Более того, мне нужен пользовательский интерфейс для управления сервисами и группами.Таким образом, при редактировании Сервиса пользователь должен иметь возможность выбирать, к каким группам он принадлежит.Аналогично, при редактировании ServiceGroup пользователь должен иметь возможность выбирать, какие сервисы принадлежат этой группе.Я уже достиг этого, установив отношение «многие ко многим» в своих доктринах.Все работает как чудо, включая сборку пользовательского интерфейса на пользовательских типах форм в Symfony2 (я использовал тип поля «сущность», чтобы позволить пользователю выбирать сервисы в редакторе ServiceGroup и группы в редакторе сервисов).Единственная проблема, с которой я столкнулся, заключается в том, что я больше не могу использовать командную строку Doctrine для обновления схемы базы данных.
Вот часть моего исходного кода объекта службы:
class Service
{
/**
* @var ArrayCollection $groups
* @ORM\ManyToMany(targetEntity="ServiceGroup")
* @ORM\JoinTable(
* name="service_servicegroup",
* joinColumns={@ORM\JoinColumn(name="service_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="servicegroup_id", referencedColumnName="id")}
* )
*/
private $groups;
}
А вот частьисходный код моей сущности ServiceGroup:
class ServiceGroup
{
/**
* @var ArrayCollection $services
* @ORM\ManyToMany(targetEntity="Service")
* @ORM\JoinTable(
* name="service_servicegroup",
* joinColumns={@ORM\JoinColumn(name="servicegroup_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="service_id", referencedColumnName="id")}
* )
*/
private $services;
}
Я использую JoinTable в обоих случаях, потому что это единственный способ найти работу, когда дело доходит до сохранения отношений в редакторах пользовательского интерфейса, что выглядит следующим образом:
Редактор службы:
Редактор службы
Имя: [Служба 1]
Группы, к которым относится эта служба:
[x] Группа A
[] Группа B
[] Группа C
[ SAVE ]
И редактор ServiceGroup:
Редактор группы
Имя: [Группа A]
Службы относятся к этой группе:
[x] Сервис 1
[] Сервис 2
[] Сервис 3
[ СОХРАНИТЬ ]
С этим много-ко-многимЯ могу использовать эти редакторы (формы) без проблем, при использовании «Многие ко многим» без аннотации JoinTable, я могу использовать только одну форму полностью, а вторая не сохраняет изменения в «Группах длякоторой принадлежит эта служба "или" Службы принадлежат к этой группе "(зависит от того, в каком направлении я устанавливаю параметры mappedBy и inversedBy в операторе аннотации" многие ко многим ").
Проблема, с которой я столкнулся, связанас механизмом генерации схемы доктрины, при попытке обновить схему с помощью команды Symfony2:
php app/console doctrine:schema:update --dump-sql
я получаю это исключение:
[Doctrine\DBAL\Schema\SchemaException]
The table with name 'service_servicegroup' already exists.
Похоже, Doctrine пытается создать 'service_servicegroup'таблица для каждого оператора JoinTable.Таким образом, он работает с текущей схемой, которую я встроил в базу данных с помощью той же команды, но пошагово, сначала, когда не определено отношение «многие ко многим», а затем только с одним определением отношения «многие ко многим» (для сервисного лица).Когда я добавил отношение «многие ко многим» ко второй сущности (ServiceGroup), мое приложение кажется работающим без проблем с точки зрения пользователя, но я больше не могу использовать команду «doctrine: schema: update».
Я понятия не имею, что не так с моим кодом, может быть, это отношение должно быть реализовано иначе, или это ошибка / ограничение Doctrine.Буду признателен за любую помощь или предложение.
ОБНОВЛЕНИЕ:
Я заметил, что мне нужно настроить отношение ManyToMany, чтобы иметь две собственные стороны.По умолчанию используется одна сторона-владелец и одна обратная сторона.Доктрина документация говорит о том, что вы можете иметь две собственные стороны в отношении ManyToMany, но не объясняет это много.Кто-нибудь может привести пример?
ВОЗМОЖНОЕ РЕШЕНИЕ:
Я нашел обходные решения, которые, возможно, не идеальны, но они работают для меня.Поскольку не существует способа иметь две собственные стороны в отношении многих ко многим, я изменил аннотацию Doctrine для своих энтитов.Служебный объект теперь является владельцем:
class Service
{
/**
* @var ArrayCollection $groups
* @ORM\ManyToMany(targetEntity="ServiceGroup", inversedBy="services", cascade={"all"})
* @ORM\JoinTable(
* name="service_to_group_assoc",
* joinColumns={@ORM\JoinColumn(name="service_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
private $groups;
}
А объект ServiceGroup является обратной стороной:
class ServiceGroup
{
/**
* @var ArrayCollection $services
* @ORM\ManyToMany(targetEntity="Service", mappedBy="groups", cascade={"all"})
*/
private $services;
}
К сожалению, в этой конфигурации отношение обновляется только при обновлении объекта службы.Когда я изменяю $ services в объекте ServiceGroup и сохраняю его, отношение останется неизменным.Итак, я изменил свой класс Controller, и с помощью небольшого решения я достиг ожидаемого результата.Это часть моего кода контроллера, которая отвечает за обновление сущности ServiceGroup (с использованием пользовательского типа формы):
// before update - get copy of currently related services:
$services = clone $group->getServices();
// ...
// when $form->isValid() etc. updating the ServiceGroup entity:
// add selected services to group
foreach($group->getServices() as $service)
{
$service->addServiceGroup($group);
$services->removeElement($service);
}
// remove unselected services from group
foreach($services as $service)
{
$service->removeServiceGroup($group);
}
Это реализации методов addServiceGroup и removeServiceGroup класса сущности Service:
/**
* Add group
*
* @param ServiceGroup $groups
*/
public function addServiceGroup(ServiceGroup $groups)
{
if(!in_array($groups, $this->groups->toArray()))
{
$this->groups[] = $groups;
}
}
/**
* Remove group
*
* @param ServiceGroup $groups
*/
public function removeServiceGroup(ServiceGroup $groups)
{
$key = $this->groups->indexOf($groups);
if($key!==FALSE)
{
$this->groups->remove($key);
}
}
Теперь у меня работает отношение «многие ко многим» с собственной (Service) и обратной (ServiceGroup) стороной, а также формы, которые обновляют как сущность, так и отношение при сохранении (формы по умолчанию для сущности Service достаточно, но дляServiceGroup я предоставил вышеупомянутые модификации).Консольные инструменты Symfony / Doctrine работают как шарм.Возможно, это можно решить лучше (проще?), Но для меня этого пока достаточно.