src/Controller/GuardianRegister/GuardianShortRegisterV3Controller.php line 137

Open in your IDE?
  1. <?php
  2. namespace App\Controller\GuardianRegister;
  3. use App\Entity\Consent;
  4. use App\Entity\Guardian;
  5. use App\Entity\GuardianRegister\GuardianRegister;
  6. use App\Entity\GuardianRegister\GuardianRegisterChild;
  7. use App\Entity\GuardianRegister\GuardianRegisterVerification;
  8. use App\Form\GuardianShortRegister\GuardianShortRegisterCodeConfirmType;
  9. use App\Form\GuardianShortRegister\GuardianShortRegisterContactStepType;
  10. use App\Form\GuardianShortRegister\GuardianShortRegisterGuardianInfoType;
  11. use App\Message\SendMailMessage;
  12. use App\Repository\ChildRepository;
  13. use App\Repository\ConfigurationRepository;
  14. use App\Repository\DiscountCouponRepository;
  15. use App\Repository\GuardianRegister\GuardianRegisterRepository;
  16. use App\Repository\GuardianRegister\GuardianRegisterVerificationRepository;
  17. use App\Repository\GuardianRepository;
  18. use App\Repository\ReminderConfigurationRepository;
  19. use App\Repository\TeacherRepository;
  20. use App\Repository\UserBlacklistRepository;
  21. use App\Service\OmnisendService;
  22. use App\Service\RefererService;
  23. use App\Service\SmsService;
  24. use App\Utils\HelperUtils;
  25. use Doctrine\ORM\EntityManagerInterface;
  26. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  27. use Symfony\Component\Form\FormError;
  28. use Symfony\Component\Form\FormInterface;
  29. use Symfony\Component\HttpFoundation\Request;
  30. use Symfony\Component\HttpFoundation\RequestStack;
  31. use Symfony\Component\HttpFoundation\Response;
  32. use Symfony\Component\Messenger\MessageBusInterface;
  33. use Symfony\Component\Routing\Annotation\Route;
  34. /**
  35. * @Route("/registracija")
  36. */
  37. class GuardianShortRegisterV3Controller extends AbstractController
  38. {
  39. private const TYPE_GUARDIAN = 'tevams';
  40. private const TYPE_STUDENT = 'mokiniai';
  41. private const LEGACY_TYPE_STUDENT = 'mokiniams';
  42. private const EXISTING_EMAIL_ERROR = 'Šiuo el.pašto adresu jau yra paskyra sistemoje. Prisijunkite <a href="https://app.corepetitus.lt">app.corepetitus.lt</a> arba susisiekite su administracija. +370 610 40 856';
  43. private const EXISTING_PHONE_ERROR = 'Šiuo telefono numeriu jau yra paskyra sistemoje. Prisijunkite <a href="https://app.corepetitus.lt">app.corepetitus.lt</a> arba susisiekite su administracija. +370 610 40 856';
  44. private const BLACKLIST_ERROR = 'Registracija negalima. Jūsų duomenys sutampa su platformos apribotų vartotojų sąrašu. Prašome susisiekti su administracija dėl tolimesnės informacijos +370 610 40 856.';
  45. private SmsService $smsService;
  46. private EntityManagerInterface $entityManager;
  47. private ReminderConfigurationRepository $reminderConfigurationRepository;
  48. private GuardianRepository $guardianRepository;
  49. private GuardianRegisterRepository $guardianRegisterRepository;
  50. private ConfigurationRepository $configurationRepository;
  51. private ChildRepository $childRepository;
  52. private MessageBusInterface $messageBus;
  53. private GuardianRegisterVerificationRepository $guardianRegisterVerificationRepository;
  54. private OmnisendService $omnisendService;
  55. private DiscountCouponRepository $discountCouponRepository;
  56. private TeacherRepository $teacherRepository;
  57. private UserBlacklistRepository $userBlacklistRepository;
  58. public function __construct(
  59. SmsService $smsService,
  60. UserBlacklistRepository $userBlacklistRepository,
  61. ChildRepository $childRepository,
  62. EntityManagerInterface $entityManager,
  63. ConfigurationRepository $configurationRepository,
  64. GuardianRepository $guardianRepository,
  65. GuardianRegisterRepository $guardianRegisterRepository,
  66. ReminderConfigurationRepository $reminderConfigurationRepository,
  67. MessageBusInterface $messageBus,
  68. GuardianRegisterVerificationRepository $guardianRegisterVerificationRepository,
  69. OmnisendService $omnisendService,
  70. DiscountCouponRepository $discountCouponRepository,
  71. TeacherRepository $teacherRepository
  72. ) {
  73. $this->smsService = $smsService;
  74. $this->entityManager = $entityManager;
  75. $this->reminderConfigurationRepository = $reminderConfigurationRepository;
  76. $this->guardianRepository = $guardianRepository;
  77. $this->guardianRegisterRepository = $guardianRegisterRepository;
  78. $this->configurationRepository = $configurationRepository;
  79. $this->childRepository = $childRepository;
  80. $this->messageBus = $messageBus;
  81. $this->guardianRegisterVerificationRepository = $guardianRegisterVerificationRepository;
  82. $this->omnisendService = $omnisendService;
  83. $this->discountCouponRepository = $discountCouponRepository;
  84. $this->teacherRepository = $teacherRepository;
  85. $this->userBlacklistRepository = $userBlacklistRepository;
  86. }
  87. /**
  88. * @Route("/", name="guardian_short_register_v2", methods={"GET", "POST"})
  89. * @Route("/{type}/{step}", name="guardian_short_register_v2_type", methods={"GET", "POST"})
  90. */
  91. public function register(Request $request, RefererService $refererService, RequestStack $requestStack, $type = null, $step = null): Response
  92. {
  93. $refererService->setReferer();
  94. if ($redirect = $this->getRedirectType($request, $type)) {
  95. return $this->redirectToStep($redirect, 1);
  96. }
  97. if (!$type) {
  98. return $this->renderStart();
  99. }
  100. if ($step === 'end') {
  101. return $this->renderSuccess($requestStack, $type);
  102. }
  103. if ((int) $step === 0) {
  104. return $this->redirectToRoute('guardian_short_register_v2');
  105. }
  106. $guardianRegister = $this->getGuardianRegisterFromSession($requestStack);
  107. if ((int) $step === 1) {
  108. return $this->handleContactStep($request, $requestStack, $guardianRegister, $type);
  109. }
  110. if ((int) $step === 2 && $this->isStudentType($type)) {
  111. return $this->handleGuardianInfoStep($request, $requestStack, $guardianRegister, $type);
  112. }
  113. if ($this->isCodeConfirmStep($type, (int) $step)) {
  114. return $this->handleCodeConfirmStep($request, $requestStack, $guardianRegister, $type);
  115. }
  116. return $this->redirectToStep($type, 1);
  117. }
  118. private function handleContactStep(Request $request, RequestStack $requestStack, GuardianRegister $guardianRegister, string $type): Response
  119. {
  120. $form = $this->createForm(GuardianShortRegisterContactStepType::class, $guardianRegister, [
  121. 'type' => $this->getFormType($type),
  122. ]);
  123. $form->handleRequest($request);
  124. if ($form->isSubmitted()) {
  125. $email = $this->normalizeEmail($guardianRegister->getEmail());
  126. $guardianRegister->setEmail($email);
  127. $this->saveStudentClass($form, $requestStack);
  128. $phone = $this->normalizePhoneForCountry($guardianRegister->getPhone(), $form->get('country')->getData());
  129. $guardianRegister->setPhone($phone);
  130. $phoneForSearch = $this->normalizeLithuanianPhone($phone);
  131. $this->validateContactEmail($form, $email, $phoneForSearch);
  132. $this->validateContactPhone($form, $email, $phoneForSearch);
  133. $this->validateReferralCode($form, $guardianRegister->getReferralCode());
  134. if ($form->isValid()) {
  135. $requestStack->getSession()->set('guardianRegister', serialize($guardianRegister));
  136. $this->saveConsent($guardianRegister, $type);
  137. return $this->redirectToStep($type, 2);
  138. }
  139. }
  140. return $this->renderStep($form, 1, $this->getTemplateType($type), $guardianRegister);
  141. }
  142. private function handleGuardianInfoStep(Request $request, RequestStack $requestStack, GuardianRegister $guardianRegister, string $type): Response
  143. {
  144. $studentEmail = $this->normalizeEmail($guardianRegister->getEmail());
  145. $form = $this->createForm(GuardianShortRegisterGuardianInfoType::class, $guardianRegister);
  146. $form->handleRequest($request);
  147. if ($form->isSubmitted()) {
  148. $email = $this->normalizeEmail($guardianRegister->getGuardianEmail());
  149. $guardianRegister->setGuardianEmail($email);
  150. $phone = $this->normalizePhoneForCountry($guardianRegister->getGuardianPhone(), $form->get('country')->getData());
  151. $guardianRegister->setGuardianPhone($phone);
  152. $phoneForSearch = $this->normalizeLithuanianPhone($phone);
  153. $this->validateGuardianContact($form, $email, $phoneForSearch);
  154. $emailsMatch = $email && $email === $studentEmail;
  155. if ($emailsMatch) {
  156. $errorMessage = 'Mokinio ir tėvo el. pašto adresai negali sutapti';
  157. $form->get('guardianEmail')->addError(new FormError($errorMessage));
  158. }
  159. if ($guardianRegister->getPhone() === $guardianRegister->getGuardianPhone()) {
  160. $form->get('guardianPhone')->addError(new FormError('Telefono numeriai negali sutapti.'));
  161. }
  162. if ($form->isValid() && !$emailsMatch) {
  163. $requestStack->getSession()->set('guardianRegister', serialize($guardianRegister));
  164. return $this->redirectToStep($type, 3);
  165. }
  166. }
  167. return $this->renderStep($form, 2, $this->getTemplateType($type), $guardianRegister);
  168. }
  169. private function handleCodeConfirmStep(Request $request, RequestStack $requestStack, GuardianRegister $guardianRegister, string $type): Response
  170. {
  171. $form = $this->createForm(GuardianShortRegisterCodeConfirmType::class, $guardianRegister);
  172. $form->handleRequest($request);
  173. $phone = (string) $this->normalizeLithuanianPhone($guardianRegister->getPhone());
  174. $verification = $this->getOrCreateVerification($phone);
  175. $this->sendVerificationSMS($verification);
  176. $code = $form->get('code')->getData();
  177. if ($code) {
  178. $this->validateVerificationCode($form, $phone, $code);
  179. if ($form->isSubmitted() && $form->isValid()) {
  180. $requestStack->getSession()->set('guardianRegister', serialize($guardianRegister));
  181. $this->finishRegistration($request, $requestStack, $guardianRegister, $type);
  182. return $this->redirectToStep($type, 'end');
  183. }
  184. }
  185. return $this->renderStep($form, $this->getCodeConfirmStep($type), $this->getTemplateType($type), $guardianRegister);
  186. }
  187. private function validateContactEmail(FormInterface $form, ?string $email, ?string $phone): void
  188. {
  189. if (!$email) {
  190. return;
  191. }
  192. $leftGuardians = $this->findGuardians($email, null, [Guardian::STATUS_LEFT['value'], Guardian::STATUS_CANCELLED['value']]);
  193. $guardians = $leftGuardians ? [] : $this->findGuardians($email);
  194. $children = $this->findChildren($email);
  195. $registrationExists = $this->hasRegistrationByEmail($email, $leftGuardians);
  196. if ($guardians || $children) {
  197. $form->get('email')->addError(new FormError(self::EXISTING_EMAIL_ERROR));
  198. $registrationExists = false;
  199. }
  200. if ($registrationExists) {
  201. $form->get('email')->addError(new FormError('Šiuo el.pašto adresu jau yra nebaigta registracija sistemoje, susisiekite su administracija. +370 610 40 856'));
  202. }
  203. if ($this->checkBlackList($email, $phone)) {
  204. $form->get('email')->addError(new FormError(self::BLACKLIST_ERROR));
  205. }
  206. }
  207. private function validateContactPhone(FormInterface $form, ?string $email, ?string $phone): void
  208. {
  209. $leftGuardians = $this->findGuardians($email, $phone, [Guardian::STATUS_LEFT['value'], Guardian::STATUS_CANCELLED['value']]);
  210. $guardians = $leftGuardians ? [] : $this->findGuardians($email, $phone);
  211. $children = $this->findChildren($email, $phone);
  212. if ($guardians || $children || $this->hasRegistrationByEmail($email, $leftGuardians, $phone)) {
  213. $form->get('phone')->addError(new FormError(self::EXISTING_PHONE_ERROR));
  214. }
  215. }
  216. private function validateGuardianContact(FormInterface $form, ?string $email, ?string $phone): void
  217. {
  218. $leftGuardians = $this->findGuardians($email, $phone, [Guardian::STATUS_LEFT['value']]);
  219. $guardians = $leftGuardians ? [] : $this->findGuardians($email, $phone);
  220. $children = $this->findChildren($email, $phone);
  221. if ($guardians || $children || $this->hasRegistrationByEmail($email, $leftGuardians, $phone)) {
  222. $form->get('guardianEmail')->addError(new FormError(self::EXISTING_EMAIL_ERROR));
  223. }
  224. if ($this->checkBlackList($email, $phone)) {
  225. $form->get('guardianEmail')->addError(new FormError(self::BLACKLIST_ERROR));
  226. }
  227. }
  228. private function validateReferralCode(FormInterface $form, ?string $referralCode): void
  229. {
  230. if (!$referralCode) {
  231. return;
  232. }
  233. $discountCoupon = $this->discountCouponRepository->findOneBy(['code' => $referralCode]);
  234. $teacher = $this->teacherRepository->findOneBy(['referralCode' => $referralCode]);
  235. $guardian = $this->guardianRepository->findOneBy(['referralCode' => $referralCode]);
  236. if (!$discountCoupon && !$teacher && !$guardian) {
  237. $form->get('referralCode')->addError(new FormError('Toks nuolaidos kodas neegzistuoja.'));
  238. }
  239. if ($discountCoupon && $discountCoupon->getValidFrom() > new \DateTime() && !$teacher && !$guardian) {
  240. $form->get('referralCode')->addError(new FormError('Toks nuolaidos kodas neegzistuoja.'));
  241. }
  242. if ($discountCoupon && $discountCoupon->getValidTo() < new \DateTime() && !$teacher && !$guardian) {
  243. $form->get('referralCode')->addError(new FormError('Nuolaidos kodo galiojimo laikas pasibaigė.'));
  244. }
  245. }
  246. private function findGuardians(?string $email = null, ?string $phone = null, array $statuses = []): array
  247. {
  248. $query = $this->guardianRepository->createQueryBuilder('g');
  249. $this->addEmailOrPhoneFilter($query, 'g.email', 'g.phoneNumber', $email, $phone);
  250. if ($statuses) {
  251. $query
  252. ->andWhere('g.status IN (:statuses)')
  253. ->setParameter('statuses', $statuses);
  254. }
  255. return $query->getQuery()->getResult();
  256. }
  257. private function findChildren(?string $email = null, ?string $phone = null): array
  258. {
  259. $query = $this->childRepository->createQueryBuilder('c');
  260. $this->addEmailOrPhoneFilter($query, 'c.email', 'c.phoneNumber', $email, $phone);
  261. return $query->getQuery()->getResult();
  262. }
  263. private function hasRegistrationByEmail(?string $email, array $leftGuardians = [], ?string $phone = null): bool
  264. {
  265. if (!$email) {
  266. return false;
  267. }
  268. $query = $this->guardianRegisterRepository->createQueryBuilder('g');
  269. $registrations = $query
  270. ->andWhere('g.email = :email')
  271. ->setParameter('email', $email)
  272. ->getQuery()
  273. ->getResult();
  274. if (!$leftGuardians) {
  275. return (bool) $registrations;
  276. }
  277. $query = $this->guardianRegisterRepository->createQueryBuilder('g');
  278. $this->addEmailOrPhoneFilter($query, 'g.email', 'g.phone', $email, $phone, 'g.guardianPhone');
  279. $newRegistrations = $query
  280. ->andWhere('g.status IN (:statuses)')
  281. ->setParameter('statuses', [GuardianRegister::STATUS_NEW['value'], GuardianRegister::STATUS_SENT['value']])
  282. ->getQuery()
  283. ->getResult();
  284. return $newRegistrations ? (bool) $registrations : false;
  285. }
  286. private function addEmailOrPhoneFilter($query, string $emailField, string $phoneField, ?string $email, ?string $phone, ?string $secondaryPhoneField = null): void
  287. {
  288. $conditions = [];
  289. if ($email) {
  290. $conditions[] = "{$emailField} = :email";
  291. $query->setParameter('email', $email);
  292. }
  293. if ($phone) {
  294. $conditions[] = "{$phoneField} LIKE :phone";
  295. $query->setParameter('phone', "%{$phone}%");
  296. if ($secondaryPhoneField) {
  297. $conditions[] = "{$secondaryPhoneField} LIKE :phone";
  298. }
  299. }
  300. if (!$conditions) {
  301. $query->andWhere('1 = 0');
  302. return;
  303. }
  304. $query->andWhere($query->expr()->orX(...$conditions));
  305. }
  306. private function finishRegistration(Request $request, RequestStack $requestStack, GuardianRegister $guardianRegister, string $type): void
  307. {
  308. $guardianRegister->setIsGuardian($this->isGuardianType($type));
  309. $guardianRegister->setPriceChange($this->getDefaultGuardianPriceChange());
  310. $this->setCurrentGuardianFoundBy($guardianRegister);
  311. $this->markDuplicateRecentRegistration($guardianRegister);
  312. $this->saveGoogleTracking($request, $guardianRegister);
  313. $this->saveSessionTracking($requestStack, $guardianRegister);
  314. $guardianRegister->setCreatedAt(new \DateTime());
  315. $this->entityManager->persist($guardianRegister);
  316. $this->entityManager->flush();
  317. $this->addStudentClassChild($requestStack, $guardianRegister);
  318. $this->sendSuccessEmail($guardianRegister);
  319. $this->trackSignup($guardianRegister);
  320. }
  321. private function getDefaultGuardianPriceChange()
  322. {
  323. $configuration = $this->configurationRepository->findOneBy(['name' => 'DEFAULT_GUARDIAN_PRICE_CHANGE']);
  324. return $configuration ? $configuration->getValue() : null;
  325. }
  326. private function setCurrentGuardianFoundBy(GuardianRegister $guardianRegister): void
  327. {
  328. $foundByEmail = false;
  329. $foundByPhone = false;
  330. if ($guardianRegister->getEmail() && $this->guardianRepository->findOneBy(['email' => $guardianRegister->getEmail()])) {
  331. $foundByEmail = true;
  332. }
  333. if ($guardianRegister->getGuardianEmail() && $this->guardianRepository->findOneBy(['email' => $guardianRegister->getGuardianEmail()])) {
  334. $foundByEmail = true;
  335. }
  336. foreach ([$guardianRegister->getPhone(), $guardianRegister->getGuardianPhone()] as $phone) {
  337. if ($this->hasExistingPhone($phone)) {
  338. $foundByPhone = true;
  339. }
  340. }
  341. if ($foundByEmail && $foundByPhone) {
  342. $guardianRegister->setCurrentGuardianFoundBy('EMAIL&TEL');
  343. } elseif ($foundByEmail) {
  344. $guardianRegister->setCurrentGuardianFoundBy('EMAIL');
  345. } elseif ($foundByPhone) {
  346. $guardianRegister->setCurrentGuardianFoundBy('TEL');
  347. }
  348. }
  349. private function hasExistingPhone(?string $phone): bool
  350. {
  351. $phoneToSearch = $this->phoneToSearch($phone);
  352. if (!$phoneToSearch) {
  353. return false;
  354. }
  355. return $this->findGuardians(null, $phoneToSearch) || $this->findChildren(null, $phoneToSearch);
  356. }
  357. private function markDuplicateRecentRegistration(GuardianRegister $guardianRegister): void
  358. {
  359. $createdAt = new \DateTime();
  360. $createdAt->modify('-3 hours');
  361. $registrationAlreadyExists = $this->guardianRegisterRepository->createQueryBuilder('g')
  362. ->andWhere('g.email = :email')
  363. ->setParameter('email', $guardianRegister->getEmail())
  364. ->andWhere('g.isGuardian = :isGuardian')
  365. ->setParameter('isGuardian', $guardianRegister->getIsGuardian())
  366. ->andWhere('g.phone = :phone')
  367. ->setParameter('phone', $guardianRegister->getPhone())
  368. ->andWhere('g.createdAt >= :createdAt')
  369. ->setParameter('createdAt', $createdAt)
  370. ->getQuery()
  371. ->getResult();
  372. if ($registrationAlreadyExists) {
  373. $guardianRegister->setIsDeleted(true);
  374. }
  375. }
  376. private function saveGoogleTracking(Request $request, GuardianRegister $guardianRegister): void
  377. {
  378. $gaCookie = $request->cookies->get('_ga');
  379. if ($gaCookie) {
  380. $guardianRegister->setGoogleClientId(str_replace('GA1.1.', '', $gaCookie));
  381. }
  382. $gaSessionCookie = $request->cookies->get('_ga_T59GXEEM42');
  383. if (!$gaSessionCookie) {
  384. return;
  385. }
  386. if (str_starts_with($gaSessionCookie, 'GA1.1.')) {
  387. $guardianRegister->setGoogleSessionId(explode('.', str_replace('GS1.1.', '', $gaSessionCookie))[0]);
  388. }
  389. if (str_starts_with($gaSessionCookie, 'GS2.1.')) {
  390. $guardianRegister->setGoogleSessionId(explode('.', str_replace('GS2.1.', '', $gaSessionCookie))[0]);
  391. }
  392. }
  393. private function saveSessionTracking(RequestStack $requestStack, GuardianRegister $guardianRegister): void
  394. {
  395. $sessionMap = [
  396. 'referer' => 'setReferer',
  397. 'refererCategory' => 'setRefererCategory',
  398. 'ad' => 'setAd',
  399. 'utm_source' => 'setUtmSource',
  400. 'utm_medium' => 'setUtmMedium',
  401. 'utm_campaign' => 'setUtmCampaign',
  402. 'handl_landing_page' => 'setLandingPage',
  403. ];
  404. foreach ($sessionMap as $sessionKey => $setter) {
  405. if ($value = $requestStack->getSession()->get($sessionKey)) {
  406. $guardianRegister->{$setter}($value);
  407. }
  408. }
  409. }
  410. private function addStudentClassChild(RequestStack $requestStack, GuardianRegister $guardianRegister): void
  411. {
  412. $guardianRegisterClass = $requestStack->getSession()->get('guardianRegisterClass');
  413. if (!$guardianRegisterClass) {
  414. return;
  415. }
  416. $guardianRegisterChild = (new GuardianRegisterChild())
  417. ->setName('Vardas1')
  418. ->setClass($guardianRegisterClass)
  419. ->setGuardianRegister($guardianRegister);
  420. $guardianRegister->addGuardianRegisterChild($guardianRegisterChild);
  421. $this->entityManager->persist($guardianRegister);
  422. $this->entityManager->persist($guardianRegisterChild);
  423. $this->entityManager->flush();
  424. }
  425. private function trackSignup(GuardianRegister $guardianRegister): void
  426. {
  427. $emailToSend = $guardianRegister->getIsGuardian()
  428. ? $guardianRegister->getEmail()
  429. : $guardianRegister->getGuardianEmail();
  430. if (!$emailToSend) {
  431. return;
  432. }
  433. $this->omnisendService->trackEvent($emailToSend, 'UserSignedUp', [
  434. 'email' => $guardianRegister->getEmail(),
  435. 'phone' => $guardianRegister->getPhone(),
  436. 'type' => $guardianRegister->getIsGuardian() ? 'parent' : 'child',
  437. ]);
  438. }
  439. private function saveConsent(GuardianRegister $guardianRegister, string $type): void
  440. {
  441. $email = $guardianRegister->getEmail();
  442. $consent = (new Consent())
  443. ->setEmail($email)
  444. ->setType($type)
  445. ->setPhone($guardianRegister->getPhone())
  446. ->setHttpRef($this->getHttpData());
  447. $this->entityManager->persist($consent);
  448. $this->entityManager->flush();
  449. if (!$email) {
  450. return;
  451. }
  452. $this->omnisendService->trackEvent($email, 'ConsentGiven', [
  453. 'email' => $email,
  454. 'type' => 'parent',
  455. ]);
  456. }
  457. private function getHttpData(): string
  458. {
  459. return json_encode([
  460. 'HTTP_USER_AGENT' => $_SERVER['HTTP_USER_AGENT'] ?? '',
  461. 'HTTP_ACCEPT' => $_SERVER['HTTP_ACCEPT'] ?? '',
  462. 'HTTP_ACCEPT_LANGUAGE' => $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '',
  463. 'HTTP_ACCEPT_ENCODING' => $_SERVER['HTTP_ACCEPT_ENCODING'] ?? '',
  464. 'HTTP_SEC_CH_UA' => $_SERVER['HTTP_SEC_CH_UA'] ?? '',
  465. 'HTTP_SEC_CH_UA_MOBILE' => $_SERVER['HTTP_SEC_CH_UA_MOBILE'] ?? '',
  466. 'HTTP_SEC_CH_UA_PLATFORM' => $_SERVER['HTTP_SEC_CH_UA_PLATFORM'] ?? '',
  467. 'HTTP_CONNECTION' => $_SERVER['HTTP_CONNECTION'] ?? '',
  468. 'HTTP_UPGRADE_INSECURE_REQUESTS' => $_SERVER['HTTP_UPGRADE_INSECURE_REQUESTS'] ?? '',
  469. 'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'] ?? '',
  470. 'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'] ?? '',
  471. 'REQUEST_URI' => $_SERVER['REQUEST_URI'] ?? '',
  472. 'REQUEST_TIME' => $_SERVER['REQUEST_TIME'] ?? time(),
  473. ]);
  474. }
  475. private function validateVerificationCode(FormInterface $form, string $phone, string $code): void
  476. {
  477. $verification = $this->guardianRegisterVerificationRepository->findOneBy(['phone' => $phone, 'status' => null]);
  478. if ($verification && $verification->getCode() === $code) {
  479. $verification->setStatus('success');
  480. $this->entityManager->persist($verification);
  481. $this->entityManager->flush();
  482. } else {
  483. $form->get('code')->addError(new FormError('Neteisingas patvirtinimo kodas. Bandykite dar kartą.'));
  484. }
  485. }
  486. private function getOrCreateVerification(string $phone): GuardianRegisterVerification
  487. {
  488. $verification = $this->guardianRegisterVerificationRepository->findOneBy(['phone' => $phone, 'status' => null]);
  489. if ($verification) {
  490. return $verification;
  491. }
  492. $verification = new GuardianRegisterVerification();
  493. $verification->setPhone($phone);
  494. $this->entityManager->persist($verification);
  495. $this->entityManager->flush();
  496. return $verification;
  497. }
  498. public function sendVerificationSMS(GuardianRegisterVerification $guardianRegisterVerification): array
  499. {
  500. $randomNumber = rand(1000, 9999);
  501. $dateNow = new \DateTime();
  502. $dateNow->modify('-3 hours');
  503. if ($guardianRegisterVerification->getSmsVerificationSentAt() && $guardianRegisterVerification->getSmsVerificationSentAt() >= $dateNow) {
  504. return [
  505. 'message' => 'Šiuo numeriu jau siuntėme patvirtinimo kodą, jis vis dar galioja. Prašome įvesti gautą kodą, į laukelį žemiau.',
  506. 'status' => true,
  507. ];
  508. }
  509. $guardianRegisterVerification->setCode($randomNumber);
  510. $guardianRegisterVerification->setSmsVerificationSentAt(new \DateTime());
  511. $this->entityManager->persist($guardianRegisterVerification);
  512. $this->entityManager->flush();
  513. $reminderObject = $this->reminderConfigurationRepository->findOneBy(['reminder_key' => 'REGISTER_PHONE_VERIFICATION']);
  514. $content = str_replace('[CODE]', $randomNumber, $reminderObject->getSmsTemplate());
  515. $phoneNumber = $guardianRegisterVerification->getPhone();
  516. $this->smsService->send($phoneNumber, $content, true);
  517. return [
  518. 'message' => "Išsiuntėme aktyvavimo kodą SMS žinute nurodytu numeriu {$phoneNumber}",
  519. 'status' => true,
  520. ];
  521. }
  522. public function checkBlackList(?string $email, ?string $phoneNumber)
  523. {
  524. if (!$email) {
  525. return false;
  526. }
  527. $phoneNumber = preg_replace('/^\+370/i', '', (string) $phoneNumber);
  528. $blackListed = $this->userBlacklistRepository->createQueryBuilder('u')
  529. ->andWhere('u.email = :email OR u.phoneNumber LIKE :phoneNumber')
  530. ->setParameter('email', $email)
  531. ->setParameter('phoneNumber', "%{$phoneNumber}")
  532. ->andWhere('u.userType = :userType')
  533. ->setParameter('userType', 'guardian')
  534. ->getQuery()
  535. ->getResult();
  536. return $blackListed ? 'Toks el. paštas jau yra sistemoje..' : false;
  537. }
  538. public function sendSuccessEmail(GuardianRegister $guardianRegister): void
  539. {
  540. $this->messageBus->dispatch(new SendMailMessage($guardianRegister->getEmail(), '', '', [], 'REGISTER_NOTIF_0'));
  541. }
  542. private function normalizePhoneForCountry(?string $phone, ?string $country): ?string
  543. {
  544. if (!$phone || !$country) {
  545. return $phone;
  546. }
  547. $countryData = HelperUtils::countryData();
  548. if (!isset($countryData[$country])) {
  549. return $phone;
  550. }
  551. $dialCode = $countryData[$country]['dialCode'];
  552. if (!str_starts_with($phone, $dialCode)) {
  553. $phone = $dialCode . $phone;
  554. }
  555. return str_replace('+370+370', '+370', $phone);
  556. }
  557. private function normalizeLithuanianPhone(?string $phone): ?string
  558. {
  559. if (!$phone) {
  560. return null;
  561. }
  562. $phone = preg_replace('/^6/i', '+3706', $phone);
  563. return preg_replace('/^86/i', '+3706', $phone);
  564. }
  565. private function phoneToSearch(?string $phone): ?string
  566. {
  567. if (!$phone || strlen($phone) <= 5) {
  568. return null;
  569. }
  570. $phone = str_replace('+3706', '', $phone);
  571. $phone = str_replace('3706', '', $phone);
  572. return preg_replace('/^86/i', '', $phone);
  573. }
  574. private function normalizeEmail(?string $email): ?string
  575. {
  576. $email = trim((string) $email);
  577. return $email === '' ? null : strtolower($email);
  578. }
  579. private function saveStudentClass(FormInterface $form, RequestStack $requestStack): void
  580. {
  581. if ($form->has('class') && $form->get('class')->getData()) {
  582. $requestStack->getSession()->set('guardianRegisterClass', $form->get('class')->getData());
  583. return;
  584. }
  585. $requestStack->getSession()->set('guardianRegisterClass', null);
  586. }
  587. private function getGuardianRegisterFromSession(RequestStack $requestStack): GuardianRegister
  588. {
  589. $guardianRegister = $requestStack->getSession()->get('guardianRegister');
  590. if ($guardianRegister) {
  591. return unserialize($guardianRegister);
  592. }
  593. return (new GuardianRegister())
  594. ->setEmail(null)
  595. ->setPhone(null);
  596. }
  597. private function getRedirectType(Request $request, ?string $type): ?string
  598. {
  599. if ($type) {
  600. return null;
  601. }
  602. $redirect = $request->query->get('redirect');
  603. if ($redirect === self::TYPE_GUARDIAN) {
  604. return self::TYPE_GUARDIAN;
  605. }
  606. return $this->isStudentType($redirect) ? self::TYPE_STUDENT : null;
  607. }
  608. private function isCodeConfirmStep(string $type, int $step): bool
  609. {
  610. return ($this->isGuardianType($type) && $step === 2) || ($this->isStudentType($type) && $step === 3);
  611. }
  612. private function getCodeConfirmStep(string $type): int
  613. {
  614. return $this->isGuardianType($type) ? 2 : 3;
  615. }
  616. private function isGuardianType(string $type): bool
  617. {
  618. return $type === self::TYPE_GUARDIAN;
  619. }
  620. private function isStudentType(?string $type): bool
  621. {
  622. return in_array($type, [self::TYPE_STUDENT, self::LEGACY_TYPE_STUDENT], true);
  623. }
  624. private function getFormType(string $type): string
  625. {
  626. return $this->isStudentType($type) ? self::LEGACY_TYPE_STUDENT : $type;
  627. }
  628. private function getTemplateType(string $type): string
  629. {
  630. return $this->isStudentType($type) ? self::LEGACY_TYPE_STUDENT : $type;
  631. }
  632. private function redirectToStep(string $type, $step): Response
  633. {
  634. return $this->redirectToRoute('guardian_short_register_v2_type', [
  635. 'type' => $this->isStudentType($type) ? self::TYPE_STUDENT : $type,
  636. 'step' => $step,
  637. ]);
  638. }
  639. private function renderStep(?FormInterface $form, $step, ?string $type, ?GuardianRegister $guardianRegister = null): Response
  640. {
  641. return $this->renderForm('guardian_register/frontend/short_registration_steps_v2.html.twig', [
  642. 'form' => $form,
  643. 'step' => $step,
  644. 'type' => $type,
  645. 'guardianRegister' => $guardianRegister,
  646. ]);
  647. }
  648. private function renderStart(): Response
  649. {
  650. return $this->render('guardian_register/frontend/short_registration_steps_v2.html.twig', [
  651. 'form' => null,
  652. 'step' => 'start',
  653. 'type' => null,
  654. ]);
  655. }
  656. private function renderSuccess(RequestStack $requestStack, string $type): Response
  657. {
  658. $guardianRegister = $requestStack->getSession()->get('guardianRegister');
  659. if ($guardianRegister) {
  660. $guardianRegister = unserialize($guardianRegister);
  661. }
  662. return $this->render('guardian_register/frontend/short_registration_success.html.twig', [
  663. 'guardianRegister' => $guardianRegister,
  664. 'step' => 'end',
  665. 'type' => $this->getTemplateType($type),
  666. ]);
  667. }
  668. }