Это не столько конкретный вопрос, сколько призыв к коллективному разуму . Многие из вас работали с Doctrine ORM и написали множество прекрасных проектов. И в ходе работы вы сталкивались с подводными камнями, типичными задачами и решениями, которымми возможно, могли бы поделиться с остальными. Ради чистоты и лаконичности кода, а так же архитектурных решений, которые ускорят разработку, давайте поделимся опытом. Возможно вам получалось создавать решения, которые были успешны (в рамках Doctrine ORM), возможно были те, которые загоняли вас в тупик.
В интернете можно найти множество best practices примеров, которые работают в рамках одной entity, но абсолютно бесполезны в реальных проектах.
От себя приведу несколько примеров:
Хорошей практикой, как я считаю, является отделение репозиториев самой доктрины, и наших репозиториев. Для работы внутри вашей бизнес логики используйте собственные классы\сервисы репозиториев, которые обязательно имплементируйте от интерфейсов.
Правила валидации для сущностей, а так же маппинг выносите в отдельные YML файлы, а не в аннотации. Это конечно спорный момент, кому что удобно, но я предпочитаю, чтобы мои сущности не зависели от ORM,
Используйтие flush с параметром, если собираетесь совершить действие только над конкретной сущностью.
Не бойтесь конструктора, прописывайте в нем зависимости вашей сущности, это сделает код более безопасным и позволит избавиться от некоторых сеттеров.
Будьте внимательны касательно новой типизации в php7 и интерфейсов, если вы создаете интерфейс для сущности и прописываете в нем возвращаемые типы, а так как же задаете скалярные типы аргументов, то после генерации Доктриной Proxy-обьектов вы получите ошибку о несоответствии класса интерфейсу. (говорят будет поправлено в 2.6 версии)
Как по мне, так у вас в голове полная каша на счет каких-либо практик. Все, что описано выше, имеет свои паттерны, названия и сферы применения, а не использование какой-то серебряной пули везде где только можно. Лучше читайте книги, учите матчасть, а не пишите глупости ради того, чтобы что-то написать.
Никаких сеттеров. Entity всегда дожна быть валидной (установка значений через конструкторы, именованные контсрукторы). Если нужно менять состояние - делаем осмысленные методы, типа:
public function updatePassword($plainPassword, EncoderInterface $encoder) {
//...
}
public function updateProfile(UserProfile $profile) {
//...
}
Вадидация должна происходить в приложении на более высоких слоях. (Валидируем request, command и прочее).
flush() всегда делаем в контроллере (в верхнем слое приложения) и забываем про такую конструкцию $em->flush($myEntity); Суть такая: наше приложение работает с бизнес-объектами (domain-objects), меняет их состояние, однако про сохранение (коммит изменений) слой модели не должен знать, это не его задача. Все изменения фиксируются в конце запроса.
Используйте Domain-events - очень удобная штука.
Иногда очень полезно отказаться от автогенерации доктриной id, можно использовать uuid.
И дострина многим не нужна, часто достаточно active-records.
Doctrine даёт большой профит только если доменна логика сложная, ну все это хорошо ложится на проектирование по модели (DDD).
Никаких сеттеров. Entity всегда дожна быть валидной - так то свойства загоняемые через конструкторы является обязательными и считается что без них модель не может существовать, а свойства изменяемые через сеттеры - необязательные. Если в модели 10-20 свойств, вы будете все через конструктор загонять?
diamond Да, с помощью value-objects (а для доктрины они же @Embeddable). Если необязательные свойства можно сделать сеттеры, но более осмысленные (сеттер на группу свойств, а не на каждое свойство).
А вообще, при некоторых подходах (CQRS) и getters не всегда нужны :)
Смотрю слайд №55 – там есть два примера, помеченных "bad", но нет примера "good". Можете привести хороший пример?
И вообще, набор отличный, спасибо. Но иногда не хватает примеров кода "как не нужно делать" + "какие проблемы будут" = "как лучше по bast practice".