Всем привет!
Вкратце архитектура такая:
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 и решение для этого ленива загрузка, что как-то совсем не внушает доверия в том, что мы движемся в нужном направлении.
CheckoutFlowController
class 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);
}
}
CheckoutFlowService
class 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;
}
}
EmailTemplateService
class 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);
}
}
Код представлен просто в качестве примера, что-то опущено, что-то не работает
Какие есть способы реализации задуманного?