custom/plugins/VirginCustomElement/src/Storefront/Subscriber/StorefrontSubscriber.php line 170

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Virgin\VirginCustomElement\Storefront\Subscriber;
  3. use DateInterval;
  4. use DateTimeImmutable;
  5. use Doctrine\DBAL\Connection;
  6. use Exception;
  7. use PDO;
  8. use Shopware\Core\Checkout\Promotion\Gateway\Template\ActiveDateRange;
  9. use Shopware\Core\Checkout\Promotion\PromotionEntity;
  10. use Shopware\Core\Content\Cms\Aggregate\CmsSlot\CmsSlotEntity;
  11. use Shopware\Core\Content\Cms\CmsPageEvents;
  12. use Shopware\Core\Content\LandingPage\LandingPageEvents;
  13. use Shopware\Core\Content\Product\ProductEntity;
  14. use Shopware\Core\Defaults;
  15. use Shopware\Core\Framework\Api\Context\AdminApiSource;
  16. use Shopware\Core\Framework\Context;
  17. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  18. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
  19. use Shopware\Core\Framework\DataAbstractionLayer\Pricing\Price;
  20. use Shopware\Core\Framework\DataAbstractionLayer\Pricing\PriceCollection;
  21. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  22. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
  23. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  24. use Shopware\Core\Framework\Uuid\Uuid;
  25. use Shopware\Core\System\SalesChannel\Context\CachedSalesChannelContextFactory;
  26. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  27. use Shopware\Core\System\Tag\TagCollection;
  28. use Shopware\Core\System\Tag\TagEntity;
  29. use Swag\PayPal\PayPal\Api\Payment\Transaction\RelatedResource\Sale;
  30. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  31. use Symfony\Component\HttpFoundation\RequestStack;
  32. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  33. use Virgin\ProductModelExtension\Custom\Club\ClubEntity;
  34. use Virgin\ProductModelExtension\Services\ClubService;
  35. use Virgin\ProductModelExtension\Services\ProductService;
  36. use Virgin\SubscriptionsConfigurator\Utils\Services\SubscriptionsConfiguratorService;
  37. use Virgin\SystemIntegration\Exception\VirginApiException;
  38. use Virgin\SystemIntegration\Services\RestApiClient;
  39. use Virgin\SystemIntegration\Services\VirginUser\VirginUser;
  40. use Virgin\VirginCustomElement\Service\LandingPageService;
  41. use Shopware\Storefront\Page\PageLoadedEvent;
  42. class StorefrontSubscriber implements EventSubscriberInterface
  43. {
  44. const string VIRGIN_CMS_SLOT_ENTITY_TYPE_PRODUCT_BOX = 'virgin-product-box';
  45. const string VIRGIN_CMS_SLOT_ENTITY_TYPE_REGISTRATION_FORM = 'virgin-registration-form';
  46. const string VIRGIN_CMS_SLOT_ENTITY_TYPE_LOGIN_FORM = 'virgin-login-form';
  47. const string SPECIAL_PROMO_PREFIX = 'promo_';
  48. const string SPECIAL_PROMO_TAG = 'special_promo';
  49. const string VIRGIN_CMS_SLOT_ENTITY_TYPE_LANDING_CONFIG = 'virgin-landing-config';
  50. /**
  51. * @var ClubService
  52. */
  53. private ClubService $clubService;
  54. /**
  55. * @var SessionInterface
  56. */
  57. private SessionInterface $session;
  58. /**
  59. * @var EntityRepository
  60. */
  61. private EntityRepository $promotionRepository;
  62. /**
  63. * @var EntityRepository
  64. */
  65. private EntityRepository $salesChannelRepository;
  66. /**
  67. * @var CachedSalesChannelContextFactory
  68. */
  69. private CachedSalesChannelContextFactory $cachedSalesChannelContextFactory;
  70. /**
  71. * @var SubscriptionsConfiguratorService
  72. */
  73. private SubscriptionsConfiguratorService $subscriptionsConfigurationService;
  74. /**
  75. * @var RestApiClient
  76. */
  77. private RestApiClient $restApiClient;
  78. /**
  79. * @var EntityRepository
  80. */
  81. private EntityRepository $tagRepository;
  82. /**
  83. * @var EntityRepository
  84. */
  85. private EntityRepository $categoryRepository;
  86. /**
  87. * @var EntityRepository
  88. */
  89. private EntityRepository $cmsSlotTranslationRepository;
  90. /** @var Connection */
  91. private Connection $connection;
  92. /**
  93. * @var RequestStack
  94. */
  95. private RequestStack $requestStack;
  96. /**
  97. * @var ProductService
  98. */
  99. private ProductService $productService;
  100. /**
  101. * @var VirginUser
  102. */
  103. private VirginUser $virginUser;
  104. private LandingPageService $landingPageService;
  105. public function __construct(
  106. ClubService $clubService,
  107. EntityRepository $promotionRepository,
  108. EntityRepository $salesChannelRepository,
  109. CachedSalesChannelContextFactory $cachedSalesChannelContextFactory,
  110. SubscriptionsConfiguratorService $subscriptionsConfigurationService,
  111. SessionInterface $session,
  112. EntityRepository $tagRepository,
  113. RestApiClient $restApiClient,
  114. EntityRepository $categoryRepository,
  115. EntityRepository $cmsSlotTranslationRepository,
  116. Connection $connection,
  117. RequestStack $requestStack,
  118. ProductService $productService,
  119. VirginUser $virginUser,
  120. LandingPageService $landingPageService
  121. ) {
  122. $this->clubService = $clubService;
  123. $this->promotionRepository = $promotionRepository;
  124. $this->salesChannelRepository = $salesChannelRepository;
  125. $this->cachedSalesChannelContextFactory = $cachedSalesChannelContextFactory;
  126. $this->subscriptionsConfigurationService = $subscriptionsConfigurationService;
  127. $this->session = $session;
  128. $this->tagRepository = $tagRepository;
  129. $this->restApiClient = $restApiClient;
  130. $this->categoryRepository = $categoryRepository;
  131. $this->cmsSlotTranslationRepository = $cmsSlotTranslationRepository;
  132. $this->connection = $connection;
  133. $this->requestStack = $requestStack;
  134. $this->productService = $productService;
  135. $this->virginUser = $virginUser;
  136. $this->landingPageService = $landingPageService;
  137. }
  138. public static function getSubscribedEvents(): array
  139. {
  140. return [
  141. CmsPageEvents::SLOT_LOADED_EVENT => 'addProductInfo',
  142. ];
  143. }
  144. /**
  145. * @param EntityLoadedEvent $event
  146. * @throws VirginApiException
  147. * @throws Exception
  148. */
  149. public function addProductInfo(EntityLoadedEvent $event): void
  150. {
  151. $context = $event->getContext();
  152. if ($context->getSource() instanceof AdminApiSource &&
  153. $context->getSource()->isAdmin() ||
  154. ($this->requestStack->getCurrentRequest()->attributes->get('_route') !== 'frontend.navigation.page' &&
  155. $this->requestStack->getCurrentRequest()->attributes->get('_route') !== 'frontend.landing.page'))
  156. return;
  157. $salesChannelContext = $this->getSalesChannelContext($context);
  158. //get landing config if there's any
  159. $landingConfig = $this->getLandingConfig($event);
  160. $virginCustomEntities = $this->getVirginCustomEntities($event);
  161. if (!$virginCustomEntities){
  162. return;
  163. }
  164. //expiration date check
  165. if ($landingConfig && $landingConfig['expirationDate']) {
  166. $isExpired = new \DateTime($landingConfig['expirationDate']) < new \DateTime();
  167. if ($isExpired) {
  168. foreach ($virginCustomEntities as $entity){
  169. $entity->setCustomFields([
  170. 'isExpired' => true,
  171. 'redirectUrl' => $landingConfig['redirectUrl'] ?? 'https://www.virginactive.it/'
  172. ]);
  173. }
  174. }
  175. }
  176. $selectedClubGuids = !empty($landingConfig) && array_key_exists('clubArray', $landingConfig) && $landingConfig['clubArray'] ? $landingConfig['clubArray'] : [];
  177. /** @var ClubEntity[] $clubs */
  178. $clubs = $this->clubService->getClubList($salesChannelContext, $selectedClubGuids, empty($selectedClubGuids));
  179. $landingPagePromoTagName = $this->getCurrentLandingPageSpecialPromoTagName();
  180. switch ($virginCustomEntities[0]->getType()){
  181. case self::VIRGIN_CMS_SLOT_ENTITY_TYPE_PRODUCT_BOX:
  182. //get promotion
  183. $promotionCriteria = new Criteria();
  184. $promotionCriteria->addAssociation('virginPromotionAttributes');
  185. $promotionCriteria->addFilter(new EqualsFilter('virginPromotionAttributes.isSpecialPromoFlow', true));
  186. $promotionCriteria->addFilter(new EqualsFilter('virginPromotionAttributes.isExerpPromotion', true));
  187. $promotionCriteria->addFilter(new ActiveDateRange());
  188. $promotionCriteria->addFilter(new EqualsFilter('active', true));
  189. /** @var PromotionEntity $specialFlowPromotion */
  190. $specialFlowPromotion = $this->promotionRepository->search(
  191. $promotionCriteria,
  192. $context
  193. )->first();
  194. $isSpecialPromoFlow = false;
  195. $isDigitalProds = true;
  196. $clubId = null;
  197. $realProductEntities = [];
  198. $tagIds = [];
  199. if ($specialFlowPromotion instanceof PromotionEntity) {
  200. $isSpecialPromoFlow = true;
  201. $isLandingConsultant = $landingConfig && array_key_exists('landingType', $landingConfig) && $landingConfig['landingType'] == 'consultant';
  202. $isLandingBocconi = $landingConfig && array_key_exists('landingType', $landingConfig) && $landingConfig['landingType'] == 'bocconi';
  203. $isLandingSaltafila = $landingConfig && array_key_exists('landingType', $landingConfig) && $landingConfig['landingType'] == 'saltafila';
  204. $isLandingExSocio = $landingConfig && array_key_exists('landingType', $landingConfig) && $landingConfig['landingType'] == 'exsoci';
  205. if ($isLandingExSocio){
  206. $this->session->set("landingExSocio", $isLandingExSocio);
  207. }
  208. if ($isLandingConsultant){
  209. $consultantId = $this->getConsultantId();
  210. if (!$consultantId){
  211. $this->redirectToHomepage();
  212. }
  213. list($centerId, $userId)= explode("p", $consultantId);
  214. $selectedClub = $this->clubService->getClubByExerpId($centerId, $salesChannelContext);
  215. $clubId = $selectedClub->getId();
  216. if ($clubId == null){
  217. $this->redirectToHomepage();
  218. }
  219. $this->session->set("consultantId", $consultantId);
  220. } else if ($isLandingSaltafila){
  221. $appointmentId = $this->getAppointmentId();
  222. $clubId = $this->getClubId();
  223. if (!$clubId){
  224. $this->redirectToHomepage();
  225. }
  226. $selectedClub = $this->clubService->getClubByExerpId($clubId, $salesChannelContext);
  227. $clubId = $selectedClub->getId();
  228. if ($clubId == null){
  229. $this->redirectToHomepage();
  230. }
  231. if ($appointmentId){
  232. $this->session->set("appointmentId", $appointmentId);
  233. }
  234. }
  235. else if (!empty($this->session->get('clubId'))) {
  236. //chatbot only
  237. $clubId = $this->session->get('clubId');
  238. $selectedClub = $this->clubService->getClubById($clubId, $salesChannelContext);
  239. } else {
  240. $selectedClub = $this->getSelectedClub($clubs, $salesChannelContext);
  241. $clubId = $selectedClub->getId();
  242. }
  243. $clubName = $selectedClub->getName();
  244. $this->session->set('clubName', $clubName);
  245. $context->assign(["selectedClub" => $selectedClub]);
  246. $context->assign(["clubName" => $clubName]);
  247. $context->assign(["clubList" => $clubs]);
  248. $context->assign(["showClubName" => $landingConfig && isset($landingConfig['showClubName']) ? $landingConfig['showClubName'] : false]);
  249. $tagIds = $this->getLandingPagePromoTagIds($context, $landingPagePromoTagName);
  250. if ($isLandingBocconi){
  251. $bocconiToken = $this->getBocconiToken();
  252. if (!$bocconiToken){
  253. $this->redirectToHomepage();
  254. }
  255. $bocconiUser = $this->getBocconiUserInfo($bocconiToken);
  256. if (!$bocconiUser){
  257. $this->redirectToHomepage();
  258. }
  259. $bocconiTagName = $bocconiUser['campaignCode'];
  260. if ($bocconiTagName){
  261. $criteria = new Criteria();
  262. $criteria->addFilter(new ContainsFilter('name', $bocconiTagName));
  263. $idTag = $this->tagRepository->searchIds($criteria, $context)->firstId();
  264. if ($idTag){
  265. array_unshift($tagIds, $idTag);
  266. }
  267. }
  268. }
  269. }
  270. foreach ($virginCustomEntities as $entity){
  271. //get products assigned via editor
  272. // 1:1 relation entity:product
  273. // can be fake or real
  274. $productEntity = $this->productService->getProductById($entity->getTranslated()['config']['product']['value'], $salesChannelContext);
  275. if ($productEntity) {
  276. $productTagsArray = $productEntity->getTags()->getElements();
  277. if (count($productTagsArray) > 0) {
  278. $specialPromoFakeProductTag = reset($productTagsArray);
  279. $isDigitalProds = !str_contains($specialPromoFakeProductTag->getName(), self::SPECIAL_PROMO_TAG);
  280. }
  281. if ($isDigitalProds) {
  282. $realProductEntities[] = $productEntity;
  283. }
  284. }
  285. }
  286. if ($isDigitalProds) {
  287. $this->session->set("isDigital", true);
  288. } else {
  289. $this->session->set("isDigital", false);
  290. }
  291. // i prodotti digitali non hanno tagsIds quindi è in or
  292. if (empty($realProductEntities) && $isSpecialPromoFlow) {
  293. $realProductEntities = $this->productService->getProductsByTags($clubId, $tagIds, $salesChannelContext);
  294. }
  295. $this->getProductBoxProducts(
  296. $realProductEntities,
  297. $landingPagePromoTagName,
  298. $salesChannelContext,
  299. $isSpecialPromoFlow,
  300. $specialFlowPromotion,
  301. $virginCustomEntities,
  302. $isDigitalProds
  303. );
  304. break;
  305. case self::VIRGIN_CMS_SLOT_ENTITY_TYPE_REGISTRATION_FORM:
  306. case self::VIRGIN_CMS_SLOT_ENTITY_TYPE_LOGIN_FORM:
  307. $entity = $virginCustomEntities[0];
  308. if ($this->virginUser->getCurrentLead() || $salesChannelContext->getCustomer()){
  309. $cardId = $this->landingPageService->getCmsPageIdFromPromoTag($landingPagePromoTagName, "cards", $salesChannelContext);
  310. $path = $this->landingPageService->getSeoUrlFromPageId($cardId, $salesChannelContext);
  311. $this->redirectTo($path);
  312. }
  313. if ($virginCustomEntities[0]->getType() == self::VIRGIN_CMS_SLOT_ENTITY_TYPE_LOGIN_FORM){
  314. $pageId = $this->landingPageService->getCmsPageIdFromPromoTag($landingPagePromoTagName, "register", $salesChannelContext);
  315. } else {
  316. $pageId = $this->landingPageService->getCmsPageIdFromPromoTag($landingPagePromoTagName, "login", $salesChannelContext);
  317. }
  318. $url = '';
  319. if ($pageId){
  320. $url = $this->landingPageService->getSEOUrlFromPageId($pageId, $salesChannelContext);
  321. }
  322. $entity->setCustomFields([
  323. 'clubs' => $clubs,
  324. 'landingCardsUrl' => $landingConfig['landingCardsUrl'] ?? '',
  325. 'landingSelectClubUrl' => $landingConfig['landingSelectClubUrl'] ?? '',
  326. 'promoTag' => $landingPagePromoTagName ?? '',
  327. 'loginRegisterUrl' => $url
  328. ]);
  329. break;
  330. default:
  331. }
  332. }
  333. /**
  334. * @param Context $context
  335. * @return SalesChannelContext
  336. * @throws \JsonException
  337. */
  338. private function getSalesChannelContext(Context $context): SalesChannelContext
  339. {
  340. $criteria = new Criteria();
  341. $criteria
  342. ->addFilter(new EqualsFilter('typeId', Defaults::SALES_CHANNEL_TYPE_STOREFRONT))
  343. ->addFilter(new EqualsFilter('active', true));
  344. $salesChannelId = $this->salesChannelRepository->searchIds($criteria, $context)->firstId();
  345. return $this->cachedSalesChannelContextFactory->create(Uuid::randomHex(), $salesChannelId);
  346. }
  347. /**
  348. * @return string
  349. */
  350. private function getCurrentLandingPageSpecialPromoTagName(): string
  351. {
  352. if ($currentNavigationPageTags = $this->session->get('currentNavigationPageTags')) {
  353. /** @var TagEntity $landingPageTag */
  354. foreach ($currentNavigationPageTags->getElements() as $landingPageTag) {
  355. if (str_contains($landingPageTagName = $landingPageTag->getName(), self::SPECIAL_PROMO_PREFIX)) {
  356. return $landingPageTagName;
  357. }
  358. }
  359. }
  360. return "";
  361. }
  362. /**
  363. * ritorna true se la landing page ha il tag che la identifica per avere il blocco di configurazione
  364. * @return bool
  365. */
  366. public function isConfigLanding(): bool
  367. {
  368. if ($currentNavigationPageTags = $this->session->get('currentNavigationPageTags')) {
  369. /** @var TagEntity $tag */
  370. foreach ($currentNavigationPageTags->getElements() as $tag) {
  371. if (strcmp($tag->getName(), $this->landingPageService::CONFIG_LANDING_TAG)===0) {
  372. return true;
  373. }
  374. }
  375. }
  376. return false;
  377. }
  378. /**
  379. * @param Context $context
  380. * @param string $landingPagePromoTagName
  381. * @return array
  382. */
  383. private function getLandingPagePromoTagIds(Context $context, string $landingPagePromoTagName): array
  384. {
  385. if (!$landingPagePromoTagName) return [];
  386. $criteria = new Criteria();
  387. $criteria->addFilter(new ContainsFilter('name', $landingPagePromoTagName . "_"));
  388. return $this->tagRepository->searchIds($criteria, $context)->getIds();
  389. }
  390. /**
  391. * @param string $landingPagePromoTagName
  392. * @param TagCollection $tags
  393. * @return int
  394. */
  395. private function getLandingPagePromoTagIndex(string $landingPagePromoTagName, TagCollection $tags): int
  396. {
  397. if ($landingPagePromoTagName) {
  398. foreach ($tags as $tag) {
  399. if (str_contains($tag->getName(), $landingPagePromoTagName) && count(explode('_', $tag->getName())) == 3)
  400. return (int)explode('_', $tag->getName())[2];
  401. }
  402. }
  403. return 0;
  404. }
  405. /**
  406. * @param array $realProductEntities
  407. * @param string $landingPagePromoTagName
  408. * @param SalesChannelContext $salesChannelContext
  409. * @param bool $isSpecialPromoFlow
  410. * @param PromotionEntity|null $specialFlowPromotion
  411. * @param $entities
  412. * @param bool $isDigitalProds
  413. * @throws Exception
  414. */
  415. public function getProductBoxProducts(array $realProductEntities, string $landingPagePromoTagName, SalesChannelContext $salesChannelContext, bool $isSpecialPromoFlow, ?PromotionEntity $specialFlowPromotion, $entities, $isDigitalProds): void
  416. {
  417. $products = [];
  418. /** @var ProductEntity $realProductEntity */
  419. foreach ($realProductEntities as $realProductEntity) {
  420. $index = $this->getLandingPagePromoTagIndex($landingPagePromoTagName, $realProductEntity->getTags());
  421. try {
  422. $type = $realProductEntity->getCustomFields()['virgin_exerp_type'];
  423. $prorataDate = (new DateTimeImmutable())->add(new DateInterval('PT0H'))->format('Y-m-d');
  424. if (array_key_exists("free_trial_days", $realProductEntity->getCustomFields())) {
  425. $prorataDate = (new DateTimeImmutable())->add(new DateInterval('PT' . ($realProductEntity->getCustomFields()['free_trial_days'] * 24) . 'H'))->format('Y-m-d');
  426. }
  427. $subReq = [
  428. 'campainCode' => '',
  429. 'centerId' => $realProductEntity->getCustomFields()['virgin_exerp_centerid'],
  430. 'clearingHouseType' => $this->restApiClient::CLEARING_HOUSE_EFT,
  431. 'personType' => $this->restApiClient::PERSONTYPE_PRIVATE,
  432. 'starDate' => $prorataDate,
  433. 'subscriptionId' => $realProductEntity->getCustomFields()['virgin_exerp_productid'],
  434. ];
  435. $response = $this->restApiClient->getSubscritionContractDetails($subReq);
  436. if ($type == "EFT") {
  437. $exerpPrice = $response->normalPeriodPrice ?? $realProductEntity->getPrice()->first()->getGross();
  438. }
  439. if ($type == "CASH") {
  440. $exerpPrice = $response->totalAmount ?? $realProductEntity->getPrice()->first()->getGross();
  441. }
  442. if ($type == "GIFTCARD") {
  443. $exerpPrice = $realProductEntity->getPrice()->first()->getGross();
  444. }
  445. $priceCollection = new PriceCollection();
  446. $priceEntity = new Price(
  447. Defaults::CURRENCY,
  448. (float) $exerpPrice,
  449. (float) $exerpPrice,
  450. $realProductEntity->getPrice()->getCurrencyPrice(Defaults::CURRENCY)->getLinked()
  451. );
  452. $priceCollection->add($priceEntity);
  453. $realProductEntity->setPrice($priceCollection);
  454. } catch (VirginApiException $e) {
  455. $isExerpDown = true;
  456. }
  457. $productCardInformation = $this->productService->getProductCardInformation($realProductEntity, $salesChannelContext);
  458. $products[] = [
  459. 'product' => $realProductEntity,
  460. 'position' => $index,
  461. 'config' => [
  462. 'promotion' => $isSpecialPromoFlow ? current($specialFlowPromotion->getExtension('virginPromotionAttributes')->getElements()) : null,
  463. 'prices' => $productCardInformation['prices'],
  464. 'productCardInformation' => $productCardInformation,
  465. 'workouts' => $productCardInformation['workouts'],
  466. 'services' => $productCardInformation['services'],
  467. 'directFlow' => isset($_SESSION['isDirectFlow']),
  468. 'exerpDown' => $isExerpDown ?? null
  469. ],
  470. 'productCardInformation' => $productCardInformation,
  471. ];
  472. }
  473. usort($products, static function (array $a, array $b) {
  474. return $a['position'] <=> $b['position'];
  475. });
  476. if ($isDigitalProds) {
  477. // se $isDigitalProds ogni entity avrà un solo array contente un solo product
  478. $products = array_values($products);
  479. foreach ($entities as $index => $entity) {
  480. $entity->getCustomFields() ? $entity->setCustomFields(
  481. array_merge(
  482. $entity->getCustomFields(),
  483. ['products' => [$products[$index]]])
  484. ) : $entity->setCustomFields(['products' => [$products[$index]]]);
  485. }
  486. } else {
  487. // altrimenti ogni entity avrà lo stesso array di prodotti
  488. foreach ($entities as $entity) {
  489. $entity->getCustomFields() ? $entity->setCustomFields(
  490. array_merge(
  491. $entity->getCustomFields(),
  492. ['products' => $products])
  493. ) : $entity->setCustomFields(['products' => $products]);
  494. }
  495. }
  496. }
  497. /**
  498. * @param $entities
  499. * @return array
  500. */
  501. public function getProductBoxEntities($entities): array
  502. {
  503. $prodBoxEntities = [];
  504. foreach ($entities as $entity) {
  505. if ($entity->getType() === self::VIRGIN_CMS_SLOT_ENTITY_TYPE_PRODUCT_BOX) {
  506. $prodBoxEntities[] = $entity;
  507. }
  508. }
  509. return $prodBoxEntities;
  510. }
  511. private function getConsultantId(){
  512. if (isset($_GET['id'])){
  513. $pattern = '/^\d{3}p[0-9]+$/i';
  514. if (preg_match($pattern, $_GET['id'])){
  515. return $_GET['id'];
  516. }
  517. }
  518. return null;
  519. }
  520. /**
  521. * @return mixed|null
  522. */
  523. private function getBocconiToken(): mixed
  524. {
  525. if ($this->session->has("bocconiToken")){
  526. $token = $this->session->get("bocconiToken");
  527. $pattern = '/[A-Za-z0-9]+/i';
  528. if (preg_match($pattern, $token)){
  529. return $token;
  530. }
  531. }
  532. return null;
  533. }
  534. /**
  535. * @param string $bocconiToken
  536. * @throws VirginApiException
  537. */
  538. public function getBocconiUserInfo(string $bocconiToken)
  539. {
  540. return $this->restApiClient->getBocconiLead($bocconiToken);
  541. }
  542. /**
  543. * @return mixed|null
  544. */
  545. private function getAppointmentId(){
  546. if (isset($_GET['appointmentId'])){
  547. return $_GET['appointmentId'];
  548. }
  549. return null;
  550. }
  551. /**
  552. * @return mixed|null
  553. */
  554. private function getClubId(){
  555. if (isset($_GET['clubId'])){
  556. $pattern = '/^\d{3}+$/i';
  557. if (preg_match($pattern, $_GET['clubId'])){
  558. return $_GET['clubId'];
  559. }
  560. }
  561. return null;
  562. }
  563. private function getClubNameParameter()
  564. {
  565. return $_GET['club'] ?? null;
  566. }
  567. /**
  568. * @param EntityLoadedEvent $event
  569. * @return array|null
  570. */
  571. private function getLandingConfig(EntityLoadedEvent $event): ? array
  572. {
  573. $context = $event->getContext();
  574. $mapCallbackFunction = function ($el){
  575. return $el['value'];
  576. };
  577. //vedere su quale landing siamo tramite tag "config/cards"
  578. if ($this->isConfigLanding()){
  579. //retrieve della config
  580. foreach ($event->getEntities() as $entity){
  581. /** @var CmsSlotEntity $entity */
  582. if ($entity->getType()==="virgin-landing-config"){
  583. return array_map($mapCallbackFunction, $entity->getTranslated()['config']);
  584. }
  585. }
  586. } else {
  587. //retrieve del tag della promo
  588. $landingPagePromoTagName = $this->getCurrentLandingPageSpecialPromoTagName();
  589. //tramite tag promo prendere trio di landing
  590. $cmsPageId = $this->landingPageService->getConfigCmsPageIdFromTag($landingPagePromoTagName, $this->getSalesChannelContext($context));
  591. //recuperare la config
  592. if ($cmsPageId){
  593. $slotId = $this->getConfigSlotId($cmsPageId);
  594. if ($slotId){
  595. return array_map($mapCallbackFunction, $this->cmsSlotTranslationRepository->search(
  596. (new Criteria())->addFilter(new EqualsFilter('cmsSlotId', $slotId), new EqualsFilter('languageId', $context->getLanguageId())),
  597. $context
  598. )->first()->getConfig());
  599. }
  600. }
  601. }
  602. return null;
  603. }
  604. /**
  605. * @return void
  606. */
  607. private function redirectToHomepage(): void
  608. {
  609. $this->redirectTo("https://www.virginactive.it/");
  610. }
  611. /**
  612. * @param string $path
  613. * @return void
  614. */
  615. private function redirectTo(string $path): void
  616. {
  617. echo '
  618. <script type="text/javascript">
  619. window.location = "'.$path.'"
  620. </script>';
  621. }
  622. /**
  623. * @param string $cmsPageId
  624. * @return string|boolean
  625. * @throws \Doctrine\DBAL\Exception
  626. * @throws \Doctrine\DBAL\Driver\Exception
  627. */
  628. private function getConfigSlotId(string $cmsPageId): bool|string
  629. {
  630. $builder = $this->connection->createQueryBuilder();
  631. return $builder->select(['LOWER(HEX(slot.id))'])
  632. ->from('cms_slot', 'slot')
  633. ->leftJoin('slot','cms_block','block','slot.cms_block_id = block.id')
  634. ->leftJoin('block','cms_section','section','block.cms_section_id = section.id')
  635. ->where('LOWER(HEX(section.cms_page_id)) = :cmsPageId')
  636. ->andWhere('slot.type = :type')
  637. ->setParameter('cmsPageId', $cmsPageId)
  638. ->setParameter('type', self::VIRGIN_CMS_SLOT_ENTITY_TYPE_LANDING_CONFIG)
  639. ->execute()
  640. ->fetchOne();
  641. }
  642. /**
  643. * @param EntityLoadedEvent $event
  644. * @return CmsSlotEntity[]
  645. */
  646. private function getVirginCustomEntities(EntityLoadedEvent $event): array
  647. {
  648. $entities = [];
  649. /** @var CmsSlotEntity $entity */
  650. foreach ($event->getEntities() as $entity) {
  651. if ($entity->getType() === self::VIRGIN_CMS_SLOT_ENTITY_TYPE_REGISTRATION_FORM ||
  652. $entity->getType() === self::VIRGIN_CMS_SLOT_ENTITY_TYPE_LOGIN_FORM ||
  653. $entity->getType() === self::VIRGIN_CMS_SLOT_ENTITY_TYPE_PRODUCT_BOX
  654. ) {
  655. $entities[] = $entity;
  656. }
  657. }
  658. return $entities;
  659. }
  660. private function getSelectedClub(array $clubs, SalesChannelContext $salesChannelContext): ClubEntity
  661. {
  662. if ($clubName = $this->getClubNameParameter()){
  663. foreach ($clubs as $club) {
  664. if ($clubName == $club->getName()) {
  665. return $club;
  666. }
  667. }
  668. }
  669. $lead = $this->virginUser->getCurrentLead();
  670. if ($lead){
  671. $clubId = $lead['clubId'];
  672. foreach ($clubs as $club) {
  673. if ($clubId == $club->getId()) {
  674. return $club;
  675. }
  676. }
  677. }
  678. return reset($clubs) ?? $this->clubService->getDefaultClub($salesChannelContext);
  679. }
  680. }