<?php
/**
* @copyright Copyright (c) 2020, Net Inventors GmbH
* @category Shopware
* @author malte
*/
namespace NetInventors\NetiNextAccessManager\Subscriber;
use Doctrine\DBAL\Exception;
use NetInventors\NetiNextAccessManager\Constants\ConfigConstants;
use NetInventors\NetiNextAccessManager\Events\BusinessEvent\CustomerActivateEvent;
use NetInventors\NetiNextAccessManager\Events\BusinessEvent\CustomerDeactivateEvent;
use \NetInventors\NetiNextAccessManager\Events\FlowEvent\CustomerActivateEvent as FlowCustomerActivateEvent;
use \NetInventors\NetiNextAccessManager\Events\FlowEvent\CustomerDeactivateEvent as FlowCustomerDeactivateEvent;
use NetInventors\NetiNextAccessManager\Extension\Content\Customer\Aggregate\CustomerAttribute\CustomerAttributeEntity;
use NetInventors\NetiNextAccessManager\Service\CheckService;
use NetInventors\NetiNextAccessManager\Service\CustomerService;
use NetInventors\NetiNextAccessManager\Service\PluginConfig;
use NetInventors\NetiNextAccessManager\Service\SalesChannelContextRestorer;
use Shopware\Core\Checkout\Customer\CustomerEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\System\SalesChannel\Context\AbstractSalesChannelContextFactory;
use Shopware\Core\System\SalesChannel\Context\SalesChannelContextService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Shopware\Core\Checkout\Customer\CustomerEvents;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class Customer implements EventSubscriberInterface
{
private bool $isFirstActivation = false;
private bool $isEventTriggered = false;
/**
* @var RequestStack
*/
private $requestStack;
/**
* @var EntityRepositoryInterface
*/
private $customerRepository;
/**
* @var PluginConfig
*/
private $pluginConfig;
/**
* @var CustomerService
*/
private $customerService;
/**
* @var EventDispatcherInterface
*/
private $eventDispatcher;
private bool $flowsAvailable;
private SalesChannelContextRestorer $salesChannelContextRestorer;
private AbstractSalesChannelContextFactory $salesChannelContextFactory;
/**
* Customer constructor.
*
* @param RequestStack $requestStack
* @param EntityRepositoryInterface $customerRepository
* @param PluginConfig $pluginConfig
* @param CustomerService $customerService
* @param EventDispatcherInterface $eventDispatcher
* @param CheckService $checkService
* @param SalesChannelContextRestorer $salesChannelContextRestorer
*/
public function __construct(
RequestStack $requestStack,
EntityRepositoryInterface $customerRepository,
PluginConfig $pluginConfig,
CustomerService $customerService,
EventDispatcherInterface $eventDispatcher,
CheckService $checkService,
SalesChannelContextRestorer $salesChannelContextRestorer,
AbstractSalesChannelContextFactory $salesChannelContextFactory
) {
$this->requestStack = $requestStack;
$this->customerRepository = $customerRepository;
$this->pluginConfig = $pluginConfig;
$this->customerService = $customerService;
$this->eventDispatcher = $eventDispatcher;
$this->flowsAvailable = $checkService->isFlowsAvailable();
$this->salesChannelContextRestorer = $salesChannelContextRestorer;
$this->salesChannelContextFactory = $salesChannelContextFactory;
}
public static function getSubscribedEvents(): array
{
return [
CustomerEvents::CUSTOMER_WRITTEN_EVENT => 'onCustomerWritten',
KernelEvents::REQUEST => 'onKernelRequest',
CustomerEvents::CUSTOMER_LOADED_EVENT => 'onCustomerLoaded',
];
}
public function onCustomerLoaded(EntityLoadedEvent $event): void
{
$entities = $event->getEntities();
/** @var CustomerEntity $entity */
foreach ($entities as $entity) {
if (null === $entity->getExtension('netiAccessManagerCustomerAttribute')) {
$this->customerService->setActiveAttribute($entity->getId(), true, $event->getContext());
}
}
}
/**
* @throws Exception
*/
public function onCustomerWritten(EntityWrittenEvent $event): void
{
$masterRequest = $this->requestStack->getMasterRequest();
if (null === $masterRequest) {
return;
}
/** @var array|mixed $attribute */
$attribute = $masterRequest->request->get('netiAccessManagerCustomerAttribute');
if (!
(
\is_array($attribute)
&& isset($attribute['activated'])
)
) {
return;
}
$customerId = $attribute['id'];
if (!\is_string($customerId)) {
throw new \UnexpectedValueException('The customer ID is not the expected type of string: '. \gettype($customerId));
}
$customer = $this->customerRepository->search(new Criteria([ $customerId ]), $event->getContext())->first();
if (!$customer instanceof CustomerEntity) {
return;
}
$pluginConfig = $this->pluginConfig->loadConfigOfSalesChannel($customer->getSalesChannelId());
if (!$pluginConfig->isActive()) {
return;
}
$isMailSendingOnChangeActivation =
$pluginConfig->getStatusChangeNotification() === ConfigConstants::STATUS_CHANGE_NOTIFICATION_CHANGE;
$context = $event->getContext();
$customer = $this->customerService->getCustomerWithSalutation($customerId, $context);
if (!$customer instanceof CustomerEntity) {
throw new \RuntimeException('Customer was not found by id '. $customerId);
}
$salesSaleChannelContext = $this->salesChannelContextFactory->create(
'',
$customer->getSalesChannelId(),
[ SalesChannelContextService::LANGUAGE_ID => $customer->getLanguageId() ]
);
$customerContext = $this->salesChannelContextRestorer->restoreByCustomer(
$customerId,
$salesSaleChannelContext
)->getContext();
if ($customer->getLanguageId() !== $context->getLanguageId()) {
$customer = $this->customerService->getCustomerWithSalutation($customerId, $customerContext);
if (!$customer instanceof CustomerEntity) {
throw new \RuntimeException('Customer was not found by id '. $customerId);
}
}
if (
$attribute['activated']
&& (
$this->isFirstActivation
|| $isMailSendingOnChangeActivation
)
) {
if (!$this->isEventTriggered) {
$this->isEventTriggered = true;
if ($this->flowsAvailable) {
/** @psalm-suppress DeprecatedClass */
$this->eventDispatcher->dispatch(new FlowCustomerActivateEvent($customerContext, $customer));
} else {
/** @psalm-suppress DeprecatedClass */
$this->eventDispatcher->dispatch(new CustomerActivateEvent($customerContext, $customer));
}
}
} elseif ($attribute['activated'] === false && $isMailSendingOnChangeActivation) {
if (!$this->isEventTriggered) {
$this->isEventTriggered = true;
if ($this->flowsAvailable) {
/** @psalm-suppress DeprecatedClass */
$this->eventDispatcher->dispatch(new FlowCustomerDeactivateEvent($customerContext, $customer));
} else {
/** @psalm-suppress DeprecatedClass */
$this->eventDispatcher->dispatch(new CustomerDeactivateEvent($customerContext, $customer));
}
}
}
}
/**
* @param RequestEvent $event
*/
public function onKernelRequest(RequestEvent $event): void
{
/** @var array|mixed $attribute */
$attribute = $event->getRequest()->request->get('netiAccessManagerCustomerAttribute');
if (
!(
\is_array($attribute)
&& isset($attribute['activated'])
&& $this->pluginConfig->isActive()
)
) {
return;
}
if (!\is_string($attribute['id'])) {
throw new \UnexpectedValueException('The customer ID is not the expected type of string: '. \gettype($attribute['id']));
}
/** @var CustomerEntity $customer */
$customer = $this->customerRepository->search(new Criteria([$attribute['id']]), Context::createDefaultContext())->first();
if (!
(
$customer instanceof CustomerEntity
&& $customer->hasExtension('netiAccessManagerCustomerAttribute')
)
) {
return;
}
/** @var CustomerAttributeEntity $extension */
$extension = $customer->getExtension('netiAccessManagerCustomerAttribute');
$this->isFirstActivation = (CustomerAttributeEntity::ACTIVATED_BY_SYSTEM === $extension->getActivatedBy());
}
}