Я работаю над проектом Symfony 2.3, который использует ORM Doctrine 2. Как и следовало ожидать, функциональность разделяется и группируется в основном независимые пакеты, чтобы допускать повторное использование кода в других проектах.
У меня есть UserBundle и ContactInfoBundle. Контактная информация отламывается, поскольку другие объекты могут иметь связанную с ними контактную информацию, однако не исключено, что система может быть построена там, где пользователи не требуют указанной контактной информации. Поэтому я бы очень предпочел, чтобы эти два не делились жесткими ссылками.
Однако создание сопоставления ассоциаций из объекта User в объект ContactInfo создает жесткую зависимость от ContactInfoBundle, как только пакет отключен. Doctrine выдает ошибки, которые ContactInfo не входит ни в одно из своих зарегистрированных пространств имен.
Мои исследования выявили несколько стратегий, которые должны противостоять этому, но ни один из них не кажется полностью функциональным:
-
Doctrine 2 ResolveTargetEntityListener
Это работает, если интерфейс фактически заменен во время выполнения. Поскольку зависимость пакета не обязательна, вполне возможно, что нет конкретной конкретной реализации (т.е. ContactInfoBundle не загружен)
Если не существует целевой объект, вся конфигурация сворачивается на себя, потому что объект-заполнитель не является сущностью (и не находится в пространстве имен /Entity ), теоретически можно связать их с объектом Mock, который на самом деле не делает что-нибудь. Но этот объект затем получает свою собственную таблицу (и ее спрашивают), открывая совершенно новую банку червей.
-
Обратное отношение
Для ContactInfo наиболее важным для пользователя является принадлежность к стороне, что делает ContactInfo собственной стороной успешно обойти необязательную часть зависимости, если задействованы только два пакета. Однако, как только третий (также необязательный) комплект желает (необязательной) ссылки с ContactInfo, создавая ContactInfo, сторона-владелец создает жесткую зависимость от ContactInfo на третьем комплекте.
Создание логической стороны, являющейся логической стороной, является конкретной ситуацией. Однако проблема универсальна, когда объект A содержит B, а C содержит B.
-
Использовать наследование с одной таблицей
До тех пор, пока необязательные связки являются единственными, которые взаимодействуют с недавно добавленной ассоциацией, давая каждому пакету собственный объект пользователя, который расширяет UserBundle\Entities\User, может работать. Однако наличие нескольких пакетов, которые расширяют единый объект, быстро приводит к тому, что это становится немного беспорядочным. Вы никогда не можете быть полностью уверены в том, какие функции доступны там, где контроллеры каким-то образом реагируют на входящие и/или выключенные пакеты (как это подтверждается механизацией Symfony 2 DependencyInjection) становится практически невозможным.
Любые идеи или идеи о том, как обойти эту проблему, приветствуются. После нескольких дней бегства в кирпичные стены я свеж от идей. Можно было бы ожидать, что у Symfony будет какой-то способ сделать это, но в документации есть только ResovleTargetEntityListener, что является неоптимальным.