<?php declare(strict_types=1);
namespace NewsletterSendinblue;
use Doctrine\DBAL\Connection;
use Exception;
use Monolog\Logger;
use NewsletterSendinblue\Core\Content\Cart\AbandonedCartDefinition;
use NewsletterSendinblue\Service\ApiClientService;
use NewsletterSendinblue\Service\ConfigService;
use NewsletterSendinblue\Service\IntegrationService;
use NewsletterSendinblue\Service\VersionProvider;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
use Shopware\Core\Framework\Plugin;
use Shopware\Core\Framework\Plugin\Context\DeactivateContext;
use Shopware\Core\Framework\Plugin\Context\InstallContext;
use Shopware\Core\Framework\Plugin\Context\UninstallContext;
use Shopware\Core\Framework\Plugin\Context\UpdateContext;
use Shopware\Core\Framework\Uuid\Uuid;
use Shopware\Core\System\SystemConfig\SystemConfigEntity;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class NewsletterSendinblue extends Plugin
{
public const ACL_ROLE_NAME = 'Brevo';
public const OLD_ACL_ROLE_NAME = 'Sendinblue';
public const INTEGRATION_LABEL = 'Brevo';
public const OLD_INTEGRATION_LABEL = 'Sendinblue';
public const PLUGIN_LABEL = 'Sendinblue';
public const USER_CONNECTION_ID_CUSTOM_FIELD = 'newsletter_sendinblue_user_connection_id';
public const CUSTOM_TABLES = [
AbandonedCartDefinition::ENTITY_NAME
];
/**
* @var IntegrationService
*/
private $integrationService;
/**
* @param ContainerBuilder $container
*/
public function build(ContainerBuilder $container): void
{
parent::build($container);
$container->setParameter('sendinblue.service_worker_path', $this->getPath() . '/Resources/js/service-worker.js');
}
/**
* @param InstallContext $installContext
*/
public function postInstall(InstallContext $installContext): void
{
$this->createAclRole($installContext->getContext());
$this->createIntegrations($installContext->getContext());
}
/**
* @param UpdateContext $updateContext
* @return void
*/
public function update(UpdateContext $updateContext): void
{
if (version_compare($updateContext->getCurrentPluginVersion(), '3.0.11', '<=')) {
try {
$this->changeIntegrationAndRoleName($updateContext->getContext());
} catch (\Throwable $exception) {
}
}
}
/**
* @param UpdateContext $updateContext
* @return void
*/
public function postUpdate(UpdateContext $updateContext): void
{
$apiClientService = $this->getApiClientService($updateContext->getCurrentShopwareVersion());
try {
$userConnectionIds = $this->getAllUserConnectionIds($updateContext->getContext());
$data = [
'plugin_version' => $updateContext->getUpdatePluginVersion(),
'shop_version' => $updateContext->getCurrentShopwareVersion()
];
foreach ($userConnectionIds as $userConnectionId) {
$apiClientService->pluginUpdated($data, $userConnectionId, $updateContext->getContext());
}
} catch (\Throwable $e) {
$apiClientService->getLogger()->addRecord(Logger::ERROR, $e->getMessage());
}
}
/**
* @param DeactivateContext $deactivateContext
*/
public function deactivate(DeactivateContext $deactivateContext): void
{
$this->removeSIBSmtpSettings($deactivateContext->getContext());
}
/**
* @param UninstallContext $uninstallContext
*/
public function uninstall(UninstallContext $uninstallContext): void
{
if (!$uninstallContext->keepUserData()) {
$this->deleteIntegrations($uninstallContext->getContext());
$this->deleteAclRole($uninstallContext->getContext());
$this->deleteAllSendinblueConfigs($uninstallContext->getContext());
$this->deleteTables();
}
}
/**
* @param Context $context
* @return string
*/
private function createAclRole(Context $context)
{
$id = md5(self::ACL_ROLE_NAME);
$roleData = [
'id' => $id,
'name' => self::ACL_ROLE_NAME,
'privileges' => ["customer.editor", "customer.viewer", "customer:read", "customer:update", "newsletter_recipient.creator", "newsletter_recipient.deleter", "newsletter_recipient.editor", "newsletter_recipient.viewer", "newsletter_recipient:create", "newsletter_recipient:delete", "newsletter_recipient:read", "newsletter_recipient:update"]
];
$aclRoleRepository = $this->container->get('acl_role.repository');
$context->scope(Context::SYSTEM_SCOPE, function (Context $context) use ($aclRoleRepository, $roleData): void {
$aclRoleRepository->upsert([$roleData], $context);
});
return $id;
}
/**
* @param Context $context
*/
private function createIntegrations(Context $context): void
{
$this->getIntegrationService()->createIntegration(self::INTEGRATION_LABEL, $context);
}
/**
* @param Context $context
*/
private function deleteIntegrations(Context $context): void
{
$this->getIntegrationService()->deleteIntegrations($context);
}
/**
* @param Context $context
*/
private function deleteAclRole(Context $context)
{
$aclRoleRepository = $this->container->get('acl_role.repository');
$context->scope(Context::SYSTEM_SCOPE, function (Context $context) use ($aclRoleRepository): void {
$aclRoleRepository->delete([['id' => md5(self::ACL_ROLE_NAME)]], $context);
$aclRoleRepository->delete([['id' => md5(self::OLD_ACL_ROLE_NAME)]], $context);
});
}
private function deleteAllSendinblueConfigs(Context $context): void
{
/** @var EntityRepositoryInterface $systemConfigRepository */
$systemConfigRepository = $this->container->get('system_config.repository');
$this->removeSIBSmtpSettings($context);
$criteria = new Criteria();
$criteria->addFilter(new ContainsFilter('configurationKey', ConfigService::CONFIG_PREFIX));
$systemConfigIds = $systemConfigRepository->searchIds($criteria, $context)->getIds();
if (empty($systemConfigIds)) {
return;
}
$ids = array_map(static function ($id) {
return ['id' => $id];
}, $systemConfigIds);
$systemConfigRepository->delete($ids, $context);
}
/**
* @param Context $context
* @return void
*/
private function removeSIBSmtpSettings(Context $context): void
{
/** @var EntityRepositoryInterface $systemConfigRepository */
$systemConfigRepository = $this->container->get('system_config.repository');
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('configurationKey', ConfigService::prepareConfigName(ConfigService::CONFIG_IS_SMTP_ENABLED)));
$systemConfigs = $systemConfigRepository->search($criteria, $context)->getElements();
if (empty($systemConfigs)) {
return;
}
/** @var SystemConfigService $systemConfigService */
$systemConfigService = $this->container->get(SystemConfigService::class);
$smtpConfigs = [
ConfigService::CORE_MAILER_AGENT_CONFIG,
ConfigService::CORE_MAILER_HOST_CONFIG,
ConfigService::CORE_MAILER_PORT_CONFIG,
ConfigService::CORE_MAILER_USERNAME_CONFIG,
ConfigService::CORE_MAILER_PASSWORD_CONFIG,
ConfigService::CORE_MAILER_SENDER_CONFIG,
ConfigService::CORE_MAILER_ENCRYPTION_CONFIG,
ConfigService::CORE_MAILER_AUTHENTICATION_CONFIG
];
foreach ($systemConfigs as $systemConfig) {
if ($systemConfig->getConfigurationValue()) {
$salesChannelId = $systemConfig->getSalesChannelId();
foreach ($smtpConfigs as $config) {
$systemConfigService->delete($config, $salesChannelId);
}
}
}
foreach ($smtpConfigs as $config) {
$systemConfigService->delete($config);
}
}
/**
* @return IntegrationService|null
*/
private function getIntegrationService(): ?IntegrationService
{
if (empty($this->integrationService)) {
if ($this->container->has(IntegrationService::class)) {
/** @var IntegrationService integrationService */
$this->integrationService = $this->container->get(IntegrationService::class);
} else {
/** @var EntityRepositoryInterface $integrationRepository */
$integrationRepository = $this->container->get('integration.repository');
/** @var EntityRepositoryInterface $aclRoleRepository */
$aclRoleRepository = $this->container->get('acl_role.repository');
/** @var SystemConfigService $systemConfigService */
$systemConfigService = $this->container->get(SystemConfigService::class);
$this->integrationService = new IntegrationService($integrationRepository, $aclRoleRepository, $systemConfigService);
}
}
return $this->integrationService;
}
/**
* @param Context $context
* @return void
*/
private function changeIntegrationAndRoleName(Context $context): void
{
$connection = $this->container->get(Connection::class);
// change acl_role name
try {
$connection->update('acl_role',
['name' => self::ACL_ROLE_NAME],
['name' => self::OLD_ACL_ROLE_NAME]
);
} catch (\Throwable $e) {
}
// change integration name
try {
$integrationRepository = $this->container->get('integration.repository');
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('customFields.sendinblue', 1));
$integrations = $integrationRepository->search($criteria, $context);
$data = [];
foreach ($integrations as $integration) {
$data[] = [
'id' => $integration->getId(),
'label' => str_replace(self::OLD_INTEGRATION_LABEL, self::INTEGRATION_LABEL, $integration->getLabel())
];
}
if (!empty($data)) {
$integrationRepository->update($data, $context);
}
} catch (\Throwable $e) {
}
}
/**
* @param string $currentSwVersion
* @return ApiClientService
*/
private function getApiClientService(string $currentSwVersion): ApiClientService
{
$configService = new ConfigService(
$this->container->get('Shopware\Core\System\SystemConfig\SystemConfigService'),
ApiClientService::SIB_BASE_URL
);
$logger = new Logger('Sendinblue');
$versionProvider = new VersionProvider(
$currentSwVersion,
$this->container->get('plugin.repository')
);
return new ApiClientService($configService, $logger, $versionProvider);
}
/**
* @param Context $context
* @return array
*/
private function getAllUserConnectionIds(Context $context): array
{
$configRepo = $this->container->get('system_config.repository');
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter(
'configurationKey',
ConfigService::CONFIG_PREFIX . ConfigService::CONFIG_USER_CONNECTION_ID)
);
$sendinblueConfigs = $configRepo->search($criteria, $context);
return $sendinblueConfigs->fmap(function (SystemConfigEntity $configEntity) {
return $configEntity->getConfigurationValue();
});
}
private function deleteTables()
{
$connection = $this->container->get(Connection::class);
foreach (self::CUSTOM_TABLES as $table) {
try {
$connection->executeStatement('DROP TABLE IF EXISTS `' . $table. '`;');
} catch (Exception $exception) {
}
}
}
}