Простое doctrine наследование с помощью MappedSuperclass

Стала тут передо мной задача, расширить некий функционал.

Приведенное наследование, может использоваться и в друхих ситуациях. Я же, просто описываю свой конкретный кейс.

Все есть «псевдо»-код

Дано: REST сервис который обрабатывает входящие данные. т.е: POST запрос с огомным payload.

Обработка: Реализован патерн Chain Of Responsibility  в котором, собственно и происходит вся обработка.

Из входящего payload, цепь строит некую структуру связанных между собой объектов, обрабатывает их и пишет в базу.

Задача: Добавить дополнительные данные внутри цепи к вложенному объекту и отправить в другой сервис (не записывая его в базу — (почему? — это уже совсем другая история)).

Пример нискольких елементов цепи

В AbstractProcessor, также лежит логика, в конечном итоге, вызывая $this->em->flush();

Почему бы не написать обработку после выполнения цепи? — Основная причина это сложная структура данных, и если использовать, например, пост процессор, алгоритм обработки усложняеться на 2 раз. —

2— ничем не обоснованное видение сложности автора. 🙂  А если, в случае с пост процессором, всю структуру (дерево) нужно обойти несколько раз.

Был выбран более эфективный, по мнению автора, алгоритм, который обрабатывает нужные данные, в нужном месте цепи, без обхода всех объектов (дерева).

Цель:

  • Расширить класс сущности без создания таблицы в базе данных.
  • Не захламлять класс entity полями которые не относятся к таблице.
  • Использовать наследника для записи в базу, что бы не использовать всякого рода датамаперы.

Т.e. (моя структура (псевдо))

Давайте посмотрим на пример кода (на самом деле псевдокода) сущности:

В данном случае нам не важно что лежит в классах связи, их описывать я не буду (хотя может и стоило, напишите в комментариях).

Первоначально я просто отнаследовал модель от ентити, но из этого ничего не вышло и начались валится ероры.

Doctrine говорит нам, что есть класс, и он расширяет сущность. Сделайте что-нибудь, чтобы решить эту проблему, потому что я не знаю, как использовать этот класс как сущность или что-то другое? Для решения этой проблемы есть некоторое решение.

Для того что бы расширить класс сущности и не создавать новую таблицу в своей базе, я буду использовать MappedSuperClass. Посмотрим на примере:

Обновил свои процессоры:

Думал, заживем …

Появилась новая проблема. Я не могу записать в базу — что эсть плохо. А как мы помним в цепи вызываеться $this->em->persist() и в конце $this->em->flush().

MappedSuperclass — не может быть сущностью, он не зависит от запросов и постоянных отношений, определяемых MappedSuperclass, должены быть однонаправленными. Это означает, что ассоциации «один-ко-многим» вообще невозможны для MappedSuperclass. Кроме того, ассоциации Many-to-Many возможны только в том случае, если MappedSuperclass используется только в одном объекте на данный момент. Для дальнейшей поддержки наследования необходимо использовать одиночные или объединенные функции наследования таблиц.

https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/inheritance-mapping.html

Но все же выход из ситуации нашелся, так как я не хотел использовать пост обработку.

Вспомнил я что у Doctrine есть чудный ResolveTargetEntityListener который позволяет мапить Интерфейс модели на одну сущность.

В конечном итоге, я добавил немного в конфиг:

С помощью ResolveTargetEntityListener вы можете разделить свои пакеты, сохраняя их структуру неизменной, но все же имея возможность определять отношения между различными объектами. Используя этот метод, ваши пакеты станет легче поддерживать.

https://symfony.com/doc/current/doctrine/resolve_target_entity.html

 

 

Описаный подход, не претендует быть «истинно правильным». Если у вас есть возражения или пожелания, их можно оставить в комментариях.

 

Ну и на последок, как многие ютюб-блогеры — «Лайки ставим, на канал подписываемся, в коменты пишем, и т.д. и т.п»

 

P.S. Спасибо за потраченное время. Если есть мысли о том что может пойти не так в предложенной схеме, велкам в комменты.

 

Leave a Reply

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.