<?php declare(strict_types=1);
namespace Virgin\LeadManager\Storefront\Subscriber;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Query\QueryBuilder;
use Shopware\Core\Content\Category\CategoryEntity;
use Shopware\Core\Content\Category\CategoryEvents;
use Shopware\Core\Content\Category\Event\NavigationLoadedEvent;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Validation\BuildValidationEvent;
use Shopware\Core\System\Language\LanguageCollection;
use Shopware\Core\System\Tag\TagCollection;
use Shopware\Core\System\Tag\TagEntity;
use Shopware\Storefront\Event\StorefrontRenderEvent;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Validator\Constraints\Regex;
use Virgin\LeadManager\Utils\Services\LeadGenerationService;
use Virgin\SystemIntegration\Exception\VirginApiException;
use Virgin\SystemIntegration\Services\RestApiClient;
class StorefrontSubscriber implements EventSubscriberInterface
{
public const string TAG_DIRECT = 'direct';
public const string TAG_FOOTER = 'footer';
/**
* @var LeadGenerationService
*/
private LeadGenerationService $leadService;
/** @var ContainerInterface */
private ContainerInterface $container;
/**
* @var RestApiClient
*/
private RestApiClient $restApiClient;
/** @var Session */
private Session $session;
/** @var EntityRepository */
private EntityRepository $languageRepository;
/**
* @param LeadGenerationService $leadService
* @param ContainerInterface $container
* @param RestApiClient $restApiClient
* @param EntityRepository $languageRepository
*/
public function __construct(
LeadGenerationService $leadService,
ContainerInterface $container,
RestApiClient $restApiClient,
EntityRepository $languageRepository
) {
$this->leadService = $leadService;
$this->container = $container;
$this->restApiClient = $restApiClient;
$session = $container->get('session');
if ($session instanceof Session){
$this->session = $session;
}
$this->languageRepository = $languageRepository;
}
/**
* @return string[]
*/
public static function getSubscribedEvents(): array
{
return [
StorefrontRenderEvent::class => 'addCustomerInfo',
KernelEvents::RESPONSE => 'onEventResponse',
CategoryEvents::CATEGORY_LOADED_EVENT => 'onLoadCategory',
NavigationLoadedEvent::class => 'onLoadNavigation',
KernelEvents::REQUEST => 'getUtmParams',
'framework.validation.customer.password.update' => 'validatePassword'
];
}
/**
* @param BuildValidationEvent $event
* @return void
*/
public function validatePassword(BuildValidationEvent $event): void
{
error_log($event->getName());
$event->getDefinition()->add('newPassword', new Regex($this->restApiClient::PASSWORD_REGEX));
}
/**
* @param RequestEvent $event
* @return void
*/
public function getUtmParams(RequestEvent $event): void
{
$utmParams = [
"utm_source" => $event->getRequest()->query->get('utm_source'),
"utm_medium" => $event->getRequest()->query->get('utm_medium'),
"utm_campaign" => $event->getRequest()->query->get('utm_campaign'),
"utm_term" => $event->getRequest()->query->get('utm_term'),
"utm_content" => $event->getRequest()->query->get('utm_content'),
];
if(array_filter($utmParams)) {
$_SESSION['utm_params'] = $utmParams;
}
}
/**
* @param StorefrontRenderEvent $event
* @return void
* @throws VirginApiException
*/
public function addCustomerInfo(StorefrontRenderEvent $event): void
{
$salesChannelContext = $event->getSalesChannelContext();
$tagCommanderVariablesArray = $this->getTagCommanderVariablesArray();
$tagCommanderVariablesArray['envLanguage'] = $this->getLanguageIsoCode($salesChannelContext->getContext());
$tagCommanderVariablesArray['envCurrency'] = $salesChannelContext->getCurrency()->getIsoCode();
if ($customer = $event->getSalesChannelContext()->getCustomer()) {
$customerEmail = $customer->getEmail();
$checkPersonResponse = json_decode($this->restApiClient->checkPerson($customerEmail), false);
if (null !== $checkPersonResponse && null !== $checkPersonResponse->exerp_User) {
$tagCommanderVariablesArray['userId'] = $checkPersonResponse->exerp_User->id;
}
$tagCommanderVariablesArray['userEmail'] = $customerEmail;
if(!empty($_SESSION['utm_params'])) {
$this->restApiClient->insertUtmParams(
$_SESSION['utm_params'],
$customerEmail,
$customer->getFirstName(),
$customer->getLastName(),
'LOGGED_USER'
);
unset($_SESSION['utm_params']);
}
$privacyConsent = $customer->getCustomFields()['privacy_consent'] ?? null;
$event->setParameter('privacy', $privacyConsent);
if(!isset($customer->getCustomFields()['lead_implicit_registration']) || !$customer->getCustomFields()['lead_implicit_registration']) {
$event->setParameter('isUserLoggedExplicit', true);
}
}else{
if(isset($_COOKIE[LeadGenerationService::ECOMMERCE_COOKIE_NAME])){
$decodedCookie = json_decode(base64_decode($_COOKIE[LeadGenerationService::ECOMMERCE_COOKIE_NAME]));
if(isset($decodedCookie->email) && $this->leadService->checkIfMailExist($decodedCookie->email, $event->getSalesChannelContext())){
$this->leadService->shadowLogin($decodedCookie->email, $event->getSalesChannelContext());
}else{
unset($_COOKIE[LeadGenerationService::ECOMMERCE_COOKIE_NAME]);
setcookie(LeadGenerationService::ECOMMERCE_COOKIE_NAME, '', time() - 3600, '/');
}
}
}
$navId = $event->getRequest()->get('navigationId');
if (null !== $navId) {
/** @var CategoryEntity $categoryEntity */
$categoryEntity = $this->leadService->checkPageCategoryWithDirectTag($navId);
if (null !== $categoryEntity) {
$tagCommanderVariablesArray['categoryId'] = $categoryEntity->getId();
$tagCommanderVariablesArray['categoryName'] = $categoryEntity->getName();
}
}
$revolutionDigitaleId = $this->leadService->getRevolutionDigitaleId($salesChannelContext);
$event->setParameter('revolutionDigitaleId', $revolutionDigitaleId);
$event->setParameter('navId', $navId);
$event->setParameter('tagCommanderVariables', $tagCommanderVariablesArray);
}
/**
* @param ResponseEvent $event
* @return void
*/
public function onEventResponse(ResponseEvent $event): void
{
$request = $event->getRequest();
$attributes = $request->attributes;
$salesChannelContext = $attributes->get('sw-sales-channel-context');
if(isset($attributes->get('_route_params')['navigationId'])){
$navigationId = $attributes->get('_route_params')['navigationId'];
if (
!$this->leadService->checkPageCategoryWithDirectTag($navigationId)
&& $this->session->has('isDirectFlow')
) {
$this->session->remove('isDirectFlow');
}
if ($this->leadService->checkPageCategory($request, $navigationId)) {
if (!$salesChannelContext->getCustomer()) {
$url = $this->container->get('router')->generate('frontend.purchase');
$event->setResponse(new RedirectResponse($url));
}
}
} else {
if ($this->session->has('isDirectFlow')) {
$this->session->remove('isDirectFlow');
}
}
if($attributes->get('_route') && $attributes->get('_route') == 'frontend.home.page'){
$url = $this->container->get('router')->generate('frontend.account.register.page');
$event->setResponse(new RedirectResponse($url));
}
}
/**
* @param EntityLoadedEvent $event
* @return void
*/
public function onLoadCategory(EntityLoadedEvent $event): void
{
$categories = $event->getEntities();
foreach ($categories as $c) {
$tagObjects = $this->getCategoryTag($c->getId());
if (!empty($tagObjects)) {
$tagEntities = [];
foreach ($tagObjects as $tagObject) {
$tag = new TagEntity();
$tag->setName($tagObject->name);
$tag->setId($tagObject->id);
$tagEntities[] = $tag;
}
$c->setTags(new TagCollection($tagEntities));
}
}
}
/**
* @param NavigationLoadedEvent $event
* @return void
*/
public function onLoadNavigation(NavigationLoadedEvent $event): void
{
$isDirect=false;
$categoryActive = $event->getNavigation()->getActive();
$this->session->set('currentNavigationPageId', $categoryActive->getId());
$currentCategoryTags = $categoryActive->getTags();
if ($currentCategoryTags) {
$this->session->set('currentNavigationPageTags', $currentCategoryTags);
foreach ($currentCategoryTags as $tagActive){
if($tagActive != null){
if($tagActive && strpos($tagActive->getName(), self::TAG_DIRECT) !== false){
$isDirect = true;
$_SESSION['isDirectFlow']= true;
$this->session->set('isDirectFlow', true);
}else{
if ($this->session->has('isDirectFlow')) {
$this->session->remove('isDirectFlow');
}
// if(isset($_SESSION['isDirectFlow'])) unset($_SESSION['isDirectFlow']);
}
}
}
}
$navTree = $event->getNavigation()->getTree();
foreach ($navTree as $k=>$t){
$tags= $t->getCategory()->getTags();
if($tags != null){
foreach ($tags as $tag){
if(($isDirect && strpos($tag->getName(),self::TAG_DIRECT) === false && strpos($tag->getName(),self::TAG_FOOTER) === false)
||(!$isDirect && strpos($tag->getName(),self::TAG_DIRECT) !== false)){
unset($navTree[$k]);
}
}
}else{ //is club?
if($isDirect){
unset($navTree[$k]);
}
}
}
$event->getNavigation()->setTree($navTree);
}
/**
* @param $categoryId
* @return array
* @throws Exception
*/
private function getCategoryTag($categoryId): array
{
$connection = $this->container->get(Connection::class);
/** @var QueryBuilder $builder */
$builder = $connection->createQueryBuilder();
$tagObj = $builder->select('LOWER(HEX(t.id)) id, t.name')
->from('tag', 't')
->leftJoin('t','category_tag','ct','t.id = ct.tag_id')
->where('ct.category_id = UNHEX( :categoryId)')
->setParameter('categoryId', $categoryId)
->execute()
->fetchAll(\PDO::FETCH_OBJ);
return $tagObj;
}
/**
* @param Context $context
* @return false|string
*/
private function getLanguageIsoCode(Context $context): false|string
{
$languageId = $context->getLanguageId();
$criteria = new Criteria([$languageId]);
$criteria->addAssociation('locale');
/** @var LanguageCollection $languageCollection */
$languageCollection = $this->languageRepository->search($criteria, $context)->getEntities();
$language = $languageCollection->get($languageId);
if ($language === null) {
return 'en';
}
$locale = $language->getLocale();
if (!$locale) {
return 'en';
}
return substr($locale->getCode(), 0, 2);
}
/**
* @return string[]
*/
private function getTagCommanderVariablesArray(): array
{
return [
'envLanguage' => '',
'envCountry' => 'Italy',
'envCurrency' => '',
'userId' => '',
'userEmail' => '',
'categoryId' => '',
'categoryName' => '',
];
}
}