Могут ли сервисы общаться между собой? Всем привет!
Вкратце архитектура такая:
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;

private $emailTemplateService;
public function __construct(
CheckoutFlowRepositoryInterface $checkoutFlowRepository,
EmailTemplateService $emailTemplateService
) {
$this->checkoutFlowRepository = $checkoutFlowRepository;
$this->emailTemplateService = $emailTemplateService;
}
public function duplicateCheckoutFlow(CheckoutFlow $checkoutFlow, string $name, string $slugName): CheckoutFlow
{
$campaign = $checkoutFlow->getCampaign();
$newCheckoutFlow = null;
$newEmailsData = null;
$currency = $checkoutFlow->getCurrency();
$currencyId = ($currency !== null) ? $currency->getId() : null;
$shippingPreset = $checkoutFlow->getShippingPreset();
$shippingPresetId = ($shippingPreset !== null) ? $shippingPreset->getId() : null;
$countriesPrices = $checkoutFlow->getCountriesPrices();
$countriesPrices = ($countriesPrices !== null) ? json_decode($countriesPrices) : null;
$metaData = $checkoutFlow->getMetaData();
$metaData = ($metaData !== null) ? json_decode($metaData) : null;
$cfTemplate = $checkoutFlow->getCfTemplate();
$emailsData = json_decode($checkoutFlow->getEmailsData());
if ($emailsData !== null) {
$newEmailsData = [];
foreach ($emailsData as $emailData) {
$emailTemplate = $this->emailTemplateService->getEmailTemplateById($emailData->email_template_id);
$newEmailTemplate = $this->emailTemplateService->duplicateEmailTemplate($emailTemplate);
$emailData->email_template_id = $newEmailTemplate->getId();
$newEmailsData[] = (array) $emailData;
}
}
$newCheckoutFlowArray = [
'name' => $name,
'slug_name' => $slugName,
'flat_rate_shipping_enable' => $checkoutFlow->getFlatRateShippingEnable(),
'currency_by_country' => $checkoutFlow->getCurrencyByCountry(),
'countries_prices' => $countriesPrices,
'campaign_id' => $campaign->getId(),
'currency_id' => $currencyId,
'checkout_flow_template_id' => $cfTemplate->getId(),
'flat_rate_shipping_price' => $checkoutFlow->getFlatRateShippingPrice(),
'meta_data' => $metaData,
'emails_data' => $newEmailsData,
'shipping_preset_id' => $shippingPresetId
];
$newCheckoutFlow = $this->checkoutFlowRepository->save(new CheckoutFlow($newCheckoutFlowArray));
return $newCheckoutFlow;
}
}
EmailTemplateServiceclass EmailTemplateService
{
private $emailTemplateRepository;
private $checkoutFlowService;

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);
}
}
Код представлен просто в качестве примера, что-то опущено, что-то не работает
Какие есть способы реализации задуманного?

21 Авг 2019 в 06:59
194 +1
0
Ответы
1

Для реализации задуманного можно использовать следующие способы:

Вариант с инжектированием EmailTemplateService в CheckoutFlowService и вызовом метода duplicateEmailTemplate напрямую из CheckoutFlowService. Данный подход представляется наиболее простым и понятным в данном контексте. Инжектирование сервисов друг в друга не является плохой практикой, если оно оправдано и логично с точки зрения логики приложения.

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

Создание отдельного сервиса, который будет отвечать за связь между двумя сущностями. Этот сервис может содержать методы для дублирования и сохранения обеих сущностей одновременно. Таким образом, вместо инжектирования EmailTemplateService в CheckoutFlowService, можно использовать этот специализированный сервис для работы с обоими сущностями.

Выбор конкретного способа зависит от конкретных требований и особенностей проекта. Важно оценить преимущества и недостатки каждого подхода и выбрать наиболее подходящий для данной ситуации.

20 Апр в 13:10
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Название заказа не должно быть пустым
Введите email
Бесплатные доработки
Гарантированные бесплатные доработки
Быстрое выполнение
Быстрое выполнение от 2 часов
Проверка работы
Проверка работы на плагиат
Интересные статьи из справочника
Поможем написать учебную работу
Название заказа не должно быть пустым
Введите email
Доверьте свою работу экспертам
Разместите заказ
Наша система отправит ваш заказ на оценку 92 588 авторам
Первые отклики появятся уже в течение 10 минут
Прямой эфир