Могут ли сервисы общаться между собой? Всем привет! Вкратце архитектура такая: entity -> repository -> service -> controller entity - представлена анемичной моделью, поэтому вся логика находится в сервисах Пример сущности - CheckoutFlow, EmailTemplate. CheckoutFlow содержит EmailTemplate сервисы CheckoutFlowService (CRUD), EmailTemplateService (CRUD) Сервисы работают с сущностями через репозитории Возникает задача дублирования CheckoutFlow, добавляем метод в сервис CheckoutFlowService::duplicate Мы дублируем сущность и сохраняем Но нам нужно также продублировать и EmailTemplate сущности соответственно и тут 2 варианта есть 1) Сервисы у нас обьщаються только с репозиториями и поэтому мы в CheckoutFlowService дублируем через репозиторий CheckoutFlowRepository свою сущность, а через репозиторий EmailTemplateRepository в этом же методе свою (EmailTemplate) Минусы подхода - что если нам нужно будем просто продублировать EmailTemplate и нам придется дублировать код 2) Мы можем создать метод в сервисе EmailTemplateService::duplicate, который бы дублировал просто EmailTemplate Плюсы - можем использовать отдельно дублирование Минусы - тогда придется инжектить в CheckoutFlowService сервис EmailTemplateService и я не знаю насколько это верно. Но еще минус в перекрестных ссылках, когда CheckoutFlowService содержит EmailTemplateService, а EmailTemplateService в свою очередь CheckoutFlowService и решение для этого ленива загрузка, что как-то совсем не внушает доверия в том, что мы движемся в нужном направлении. CheckoutFlowControllerclass CheckoutFlowController { private $checkoutFlowService; public function __construct( CheckoutFlowService $checkoutFlowService ) { $this->checkoutFlowService = $checkoutFlowService; }
public function duplicate( Request $request, int $id ): Response { $body = $request->request->all(); $checkoutFlow = $this->checkoutFlowService->getCheckoutFlowById($id); $newCheckoutFlow = $this->checkoutFlowService->duplicateCheckoutFlow( $checkoutFlow, $body['name'], $body['slug_name'] ); $data = [ 'checkout_flow' => $newCheckoutFlow ]; $response = new JSendResponse(JSendResponse::SUCCESS, $data); return new JsonResponse($response, Response::HTTP_OK); } } CheckoutFlowServiceclass CheckoutFlowService { private $checkoutFlowRepository;
public function __construct( EmailTemplateRepositoryInterface $emailTemplateRepository, CheckoutFlowService $checkoutFlowService ) { $this->emailTemplateRepository = $emailTemplateRepository; $this->checkoutFlowService = $checkoutFlowService; } public function addEmailTemplate(array $fields): EmailTemplate { $emailTemplate = new EmailTemplate(); $emailTemplate->setSubject($fields['subject']); $emailTemplate->setData($fields['data']); return $this->emailTemplateRepository->save($emailTemplate); } public function duplicateEmailTemplate(EmailTemplate $emailTemplate): EmailTemplate { $newEmailTemplateArray = [ 'subject' => $emailTemplate->getSubject(), 'data' => $emailTemplate->getData() ]; return $this->addEmailTemplate($newEmailTemplateArray); } } Код представлен просто в качестве примера, что-то опущено, что-то не работает Какие есть способы реализации задуманного?
Для реализации задуманного можно использовать следующие способы:
Вариант с инжектированием EmailTemplateService в CheckoutFlowService и вызовом метода duplicateEmailTemplate напрямую из CheckoutFlowService. Данный подход представляется наиболее простым и понятным в данном контексте. Инжектирование сервисов друг в друга не является плохой практикой, если оно оправдано и логично с точки зрения логики приложения.
Использование исполнителя команды или шаблона наблюдатель. В этом случае при дублировании CheckoutFlow сущности можно использовать паттерн наблюдатель, который будет следить за событиями и автоматически дублировать EmailTemplate сущности. Также можно создать исполнителя команды, который будет обрабатывать дублирование CheckoutFlow и отправлять команду на дублирование EmailTemplate. Этот подход может усложнить структуру кода, но обеспечит более гибкую и расширяемую архитектуру.
Создание отдельного сервиса, который будет отвечать за связь между двумя сущностями. Этот сервис может содержать методы для дублирования и сохранения обеих сущностей одновременно. Таким образом, вместо инжектирования EmailTemplateService в CheckoutFlowService, можно использовать этот специализированный сервис для работы с обоими сущностями.
Выбор конкретного способа зависит от конкретных требований и особенностей проекта. Важно оценить преимущества и недостатки каждого подхода и выбрать наиболее подходящий для данной ситуации.
Для реализации задуманного можно использовать следующие способы:
Вариант с инжектированием EmailTemplateService в CheckoutFlowService и вызовом метода duplicateEmailTemplate напрямую из CheckoutFlowService. Данный подход представляется наиболее простым и понятным в данном контексте. Инжектирование сервисов друг в друга не является плохой практикой, если оно оправдано и логично с точки зрения логики приложения.
Использование исполнителя команды или шаблона наблюдатель. В этом случае при дублировании CheckoutFlow сущности можно использовать паттерн наблюдатель, который будет следить за событиями и автоматически дублировать EmailTemplate сущности. Также можно создать исполнителя команды, который будет обрабатывать дублирование CheckoutFlow и отправлять команду на дублирование EmailTemplate. Этот подход может усложнить структуру кода, но обеспечит более гибкую и расширяемую архитектуру.
Создание отдельного сервиса, который будет отвечать за связь между двумя сущностями. Этот сервис может содержать методы для дублирования и сохранения обеих сущностей одновременно. Таким образом, вместо инжектирования EmailTemplateService в CheckoutFlowService, можно использовать этот специализированный сервис для работы с обоими сущностями.
Выбор конкретного способа зависит от конкретных требований и особенностей проекта. Важно оценить преимущества и недостатки каждого подхода и выбрать наиболее подходящий для данной ситуации.