src/Controller/GuardianRegister/GuardianShortRegisterV3Controller.php line 98

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'], Guardian::STATUS_OVERPAID['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'], Guardian::STATUS_OVERPAID['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'], Guardian::STATUS_OVERPAID['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->createQueryBuilder('dc')
  234. ->where('dc.code = :code')
  235. ->andWhere('dc.validTo > :now and dc.validFrom < :now')
  236. ->setParameter('code', $referralCode)
  237. ->setParameter('now', new \DateTime())
  238. ->getQuery()
  239. ->setMaxResults(1)
  240. ->getOneOrNullResult();
  241. $teacher = $this->teacherRepository->findOneBy(['referralCode' => $referralCode]);
  242. $guardian = $this->guardianRepository->findOneBy(['referralCode' => $referralCode]);
  243. if (!$discountCoupon && !$teacher && !$guardian) {
  244. $form->get('referralCode')->addError(new FormError('Toks nuolaidos kodas neegzistuoja.'));
  245. }
  246. if ($discountCoupon && $discountCoupon->getValidFrom() > new \DateTime() && !$teacher && !$guardian) {
  247. $form->get('referralCode')->addError(new FormError('Toks nuolaidos kodas neegzistuoja.'));
  248. }
  249. if ($discountCoupon && $discountCoupon->getValidTo() < new \DateTime() && !$teacher && !$guardian) {
  250. $form->get('referralCode')->addError(new FormError('Nuolaidos kodo galiojimo laikas pasibaigė.22'));
  251. }
  252. }
  253. private function findGuardians(?string $email = null, ?string $phone = null, array $statuses = []): array
  254. {
  255. $query = $this->guardianRepository->createQueryBuilder('g');
  256. $this->addEmailOrPhoneFilter($query, 'g.email', 'g.phoneNumber', $email, $phone);
  257. if ($statuses) {
  258. $query
  259. ->andWhere('g.status IN (:statuses)')
  260. ->setParameter('statuses', $statuses);
  261. }
  262. return $query->getQuery()->getResult();
  263. }
  264. private function findChildren(?string $email = null, ?string $phone = null): array
  265. {
  266. $query = $this->childRepository->createQueryBuilder('c');
  267. $this->addEmailOrPhoneFilter($query, 'c.email', 'c.phoneNumber', $email, $phone);
  268. return $query->getQuery()->getResult();
  269. }
  270. private function hasRegistrationByEmail(?string $email, array $leftGuardians = [], ?string $phone = null): bool
  271. {
  272. if (!$email) {
  273. return false;
  274. }
  275. $query = $this->guardianRegisterRepository->createQueryBuilder('g');
  276. $registrations = $query
  277. ->andWhere('g.email = :email')
  278. ->setParameter('email', $email)
  279. ->getQuery()
  280. ->getResult();
  281. if (!$leftGuardians) {
  282. return (bool) $registrations;
  283. }
  284. $query = $this->guardianRegisterRepository->createQueryBuilder('g');
  285. $this->addEmailOrPhoneFilter($query, 'g.email', 'g.phone', $email, $phone, 'g.guardianPhone');
  286. $newRegistrations = $query
  287. ->andWhere('g.status IN (:statuses)')
  288. ->setParameter('statuses', [GuardianRegister::STATUS_NEW['value'], GuardianRegister::STATUS_SENT['value']])
  289. ->getQuery()
  290. ->getResult();
  291. return $newRegistrations ? (bool) $registrations : false;
  292. }
  293. private function addEmailOrPhoneFilter($query, string $emailField, string $phoneField, ?string $email, ?string $phone, ?string $secondaryPhoneField = null): void
  294. {
  295. $conditions = [];
  296. if ($email) {
  297. $conditions[] = "{$emailField} = :email";
  298. $query->setParameter('email', $email);
  299. }
  300. if ($phone) {
  301. $conditions[] = "{$phoneField} LIKE :phone";
  302. $query->setParameter('phone', "%{$phone}%");
  303. if ($secondaryPhoneField) {
  304. $conditions[] = "{$secondaryPhoneField} LIKE :phone";
  305. }
  306. }
  307. if (!$conditions) {
  308. $query->andWhere('1 = 0');
  309. return;
  310. }
  311. $query->andWhere($query->expr()->orX(...$conditions));
  312. }
  313. private function finishRegistration(Request $request, RequestStack $requestStack, GuardianRegister $guardianRegister, string $type): void
  314. {
  315. $guardianRegister->setIsGuardian($this->isGuardianType($type));
  316. $guardianRegister->setPriceChange($this->getDefaultGuardianPriceChange());
  317. $this->setCurrentGuardianFoundBy($guardianRegister);
  318. $this->markDuplicateRecentRegistration($guardianRegister);
  319. $this->saveGoogleTracking($request, $guardianRegister);
  320. $this->saveSessionTracking($requestStack, $guardianRegister);
  321. $guardianRegister->setCreatedAt(new \DateTime());
  322. $this->entityManager->persist($guardianRegister);
  323. $this->entityManager->flush();
  324. $this->addStudentClassChild($requestStack, $guardianRegister);
  325. $this->sendSuccessEmail($guardianRegister);
  326. $this->trackSignup($guardianRegister);
  327. }
  328. private function getDefaultGuardianPriceChange()
  329. {
  330. $configuration = $this->configurationRepository->findOneBy(['name' => 'DEFAULT_GUARDIAN_PRICE_CHANGE']);
  331. return $configuration ? $configuration->getValue() : null;
  332. }
  333. private function setCurrentGuardianFoundBy(GuardianRegister $guardianRegister): void
  334. {
  335. $foundByEmail = false;
  336. $foundByPhone = false;
  337. if ($guardianRegister->getEmail() && $this->guardianRepository->findOneBy(['email' => $guardianRegister->getEmail()])) {
  338. $foundByEmail = true;
  339. }
  340. if ($guardianRegister->getGuardianEmail() && $this->guardianRepository->findOneBy(['email' => $guardianRegister->getGuardianEmail()])) {
  341. $foundByEmail = true;
  342. }
  343. foreach ([$guardianRegister->getPhone(), $guardianRegister->getGuardianPhone()] as $phone) {
  344. if ($this->hasExistingPhone($phone)) {
  345. $foundByPhone = true;
  346. }
  347. }
  348. if ($foundByEmail && $foundByPhone) {
  349. $guardianRegister->setCurrentGuardianFoundBy('EMAIL&TEL');
  350. } elseif ($foundByEmail) {
  351. $guardianRegister->setCurrentGuardianFoundBy('EMAIL');
  352. } elseif ($foundByPhone) {
  353. $guardianRegister->setCurrentGuardianFoundBy('TEL');
  354. }
  355. }
  356. private function hasExistingPhone(?string $phone): bool
  357. {
  358. $phoneToSearch = $this->phoneToSearch($phone);
  359. if (!$phoneToSearch) {
  360. return false;
  361. }
  362. return $this->findGuardians(null, $phoneToSearch) || $this->findChildren(null, $phoneToSearch);
  363. }
  364. private function markDuplicateRecentRegistration(GuardianRegister $guardianRegister): void
  365. {
  366. $createdAt = new \DateTime();
  367. $createdAt->modify('-3 hours');
  368. $registrationAlreadyExists = $this->guardianRegisterRepository->createQueryBuilder('g')
  369. ->andWhere('g.email = :email')
  370. ->setParameter('email', $guardianRegister->getEmail())
  371. ->andWhere('g.isGuardian = :isGuardian')
  372. ->setParameter('isGuardian', $guardianRegister->getIsGuardian())
  373. ->andWhere('g.phone = :phone')
  374. ->setParameter('phone', $guardianRegister->getPhone())
  375. ->andWhere('g.createdAt >= :createdAt')
  376. ->setParameter('createdAt', $createdAt)
  377. ->getQuery()
  378. ->getResult();
  379. if ($registrationAlreadyExists) {
  380. $guardianRegister->setIsDeleted(true);
  381. }
  382. }
  383. private function saveGoogleTracking(Request $request, GuardianRegister $guardianRegister): void
  384. {
  385. $gaCookie = $request->cookies->get('_ga');
  386. if ($gaCookie) {
  387. $guardianRegister->setGoogleClientId(str_replace('GA1.1.', '', $gaCookie));
  388. }
  389. $gaSessionCookie = $request->cookies->get('_ga_T59GXEEM42');
  390. if (!$gaSessionCookie) {
  391. return;
  392. }
  393. if (str_starts_with($gaSessionCookie, 'GA1.1.')) {
  394. $guardianRegister->setGoogleSessionId(explode('.', str_replace('GS1.1.', '', $gaSessionCookie))[0]);
  395. }
  396. if (str_starts_with($gaSessionCookie, 'GS2.1.')) {
  397. $guardianRegister->setGoogleSessionId(explode('.', str_replace('GS2.1.', '', $gaSessionCookie))[0]);
  398. }
  399. }
  400. private function saveSessionTracking(RequestStack $requestStack, GuardianRegister $guardianRegister): void
  401. {
  402. $sessionMap = [
  403. 'referer' => 'setReferer',
  404. 'refererCategory' => 'setRefererCategory',
  405. 'ad' => 'setAd',
  406. 'utm_source' => 'setUtmSource',
  407. 'utm_medium' => 'setUtmMedium',
  408. 'utm_campaign' => 'setUtmCampaign',
  409. 'handl_landing_page' => 'setLandingPage',
  410. ];
  411. foreach ($sessionMap as $sessionKey => $setter) {
  412. if ($value = $requestStack->getSession()->get($sessionKey)) {
  413. $guardianRegister->{$setter}($value);
  414. }
  415. }
  416. }
  417. private function addStudentClassChild(RequestStack $requestStack, GuardianRegister $guardianRegister): void
  418. {
  419. $guardianRegisterClass = $requestStack->getSession()->get('guardianRegisterClass');
  420. if (!$guardianRegisterClass) {
  421. return;
  422. }
  423. $guardianRegisterChild = (new GuardianRegisterChild())
  424. ->setName('Vardas1')
  425. ->setClass($guardianRegisterClass)
  426. ->setGuardianRegister($guardianRegister);
  427. $guardianRegister->addGuardianRegisterChild($guardianRegisterChild);
  428. $this->entityManager->persist($guardianRegister);
  429. $this->entityManager->persist($guardianRegisterChild);
  430. $this->entityManager->flush();
  431. }
  432. private function trackSignup(GuardianRegister $guardianRegister): void
  433. {
  434. $emailToSend = $guardianRegister->getIsGuardian()
  435. ? $guardianRegister->getEmail()
  436. : $guardianRegister->getGuardianEmail();
  437. if (!$emailToSend) {
  438. return;
  439. }
  440. $this->omnisendService->trackEvent($emailToSend, 'UserSignedUp', [
  441. 'email' => $guardianRegister->getEmail(),
  442. 'phone' => $guardianRegister->getPhone(),
  443. 'type' => $guardianRegister->getIsGuardian() ? 'parent' : 'child',
  444. ]);
  445. }
  446. private function saveConsent(GuardianRegister $guardianRegister, string $type): void
  447. {
  448. $email = $guardianRegister->getEmail();
  449. $consent = (new Consent())
  450. ->setEmail($email)
  451. ->setType($type)
  452. ->setPhone($guardianRegister->getPhone())
  453. ->setHttpRef($this->getHttpData());
  454. $this->entityManager->persist($consent);
  455. $this->entityManager->flush();
  456. if (!$email) {
  457. return;
  458. }
  459. $this->omnisendService->trackEvent($email, 'ConsentGiven', [
  460. 'email' => $email,
  461. 'type' => 'parent',
  462. ]);
  463. }
  464. private function getHttpData(): string
  465. {
  466. return json_encode([
  467. 'HTTP_USER_AGENT' => $_SERVER['HTTP_USER_AGENT'] ?? '',
  468. 'HTTP_ACCEPT' => $_SERVER['HTTP_ACCEPT'] ?? '',
  469. 'HTTP_ACCEPT_LANGUAGE' => $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '',
  470. 'HTTP_ACCEPT_ENCODING' => $_SERVER['HTTP_ACCEPT_ENCODING'] ?? '',
  471. 'HTTP_SEC_CH_UA' => $_SERVER['HTTP_SEC_CH_UA'] ?? '',
  472. 'HTTP_SEC_CH_UA_MOBILE' => $_SERVER['HTTP_SEC_CH_UA_MOBILE'] ?? '',
  473. 'HTTP_SEC_CH_UA_PLATFORM' => $_SERVER['HTTP_SEC_CH_UA_PLATFORM'] ?? '',
  474. 'HTTP_CONNECTION' => $_SERVER['HTTP_CONNECTION'] ?? '',
  475. 'HTTP_UPGRADE_INSECURE_REQUESTS' => $_SERVER['HTTP_UPGRADE_INSECURE_REQUESTS'] ?? '',
  476. 'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'] ?? '',
  477. 'REQUEST_METHOD' => $_SERVER['REQUEST_METHOD'] ?? '',
  478. 'REQUEST_URI' => $_SERVER['REQUEST_URI'] ?? '',
  479. 'REQUEST_TIME' => $_SERVER['REQUEST_TIME'] ?? time(),
  480. ]);
  481. }
  482. private function validateVerificationCode(FormInterface $form, string $phone, string $code): void
  483. {
  484. $verification = $this->guardianRegisterVerificationRepository->findOneBy(['phone' => $phone, 'status' => null]);
  485. if ($verification && $verification->getCode() === $code) {
  486. $verification->setStatus('success');
  487. $this->entityManager->persist($verification);
  488. $this->entityManager->flush();
  489. } else {
  490. $form->get('code')->addError(new FormError('Neteisingas patvirtinimo kodas. Bandykite dar kartą.'));
  491. }
  492. }
  493. private function getOrCreateVerification(string $phone): GuardianRegisterVerification
  494. {
  495. $verification = $this->guardianRegisterVerificationRepository->findOneBy(['phone' => $phone, 'status' => null]);
  496. if ($verification) {
  497. return $verification;
  498. }
  499. $verification = new GuardianRegisterVerification();
  500. $verification->setPhone($phone);
  501. $this->entityManager->persist($verification);
  502. $this->entityManager->flush();
  503. return $verification;
  504. }
  505. public function sendVerificationSMS(GuardianRegisterVerification $guardianRegisterVerification): array
  506. {
  507. $randomNumber = rand(1000, 9999);
  508. $dateNow = new \DateTime();
  509. $dateNow->modify('-3 hours');
  510. if ($guardianRegisterVerification->getSmsVerificationSentAt() && $guardianRegisterVerification->getSmsVerificationSentAt() >= $dateNow) {
  511. return [
  512. 'message' => 'Šiuo numeriu jau siuntėme patvirtinimo kodą, jis vis dar galioja. Prašome įvesti gautą kodą, į laukelį žemiau.',
  513. 'status' => true,
  514. ];
  515. }
  516. $guardianRegisterVerification->setCode($randomNumber);
  517. $guardianRegisterVerification->setSmsVerificationSentAt(new \DateTime());
  518. $this->entityManager->persist($guardianRegisterVerification);
  519. $this->entityManager->flush();
  520. $reminderObject = $this->reminderConfigurationRepository->findOneBy(['reminder_key' => 'REGISTER_PHONE_VERIFICATION']);
  521. $content = str_replace('[CODE]', $randomNumber, $reminderObject->getSmsTemplate());
  522. $phoneNumber = $guardianRegisterVerification->getPhone();
  523. $this->smsService->send($phoneNumber, $content, true);
  524. return [
  525. 'message' => "Išsiuntėme aktyvavimo kodą SMS žinute nurodytu numeriu {$phoneNumber}",
  526. 'status' => true,
  527. ];
  528. }
  529. public function checkBlackList(?string $email, ?string $phoneNumber)
  530. {
  531. if (!$email) {
  532. return false;
  533. }
  534. $phoneNumber = preg_replace('/^\+370/i', '', (string) $phoneNumber);
  535. $blackListed = $this->userBlacklistRepository->createQueryBuilder('u')
  536. ->andWhere('u.email = :email OR u.phoneNumber LIKE :phoneNumber')
  537. ->setParameter('email', $email)
  538. ->setParameter('phoneNumber', "%{$phoneNumber}")
  539. ->andWhere('u.userType = :userType')
  540. ->setParameter('userType', 'guardian')
  541. ->getQuery()
  542. ->getResult();
  543. return $blackListed ? 'Toks el. paštas jau yra sistemoje..' : false;
  544. }
  545. public function sendSuccessEmail(GuardianRegister $guardianRegister): void
  546. {
  547. $this->messageBus->dispatch(new SendMailMessage($guardianRegister->getEmail(), '', '', [], 'REGISTER_NOTIF_0'));
  548. }
  549. private function normalizePhoneForCountry(?string $phone, ?string $country): ?string
  550. {
  551. if (!$phone || !$country) {
  552. return $phone;
  553. }
  554. $countryData = HelperUtils::countryData();
  555. if (!isset($countryData[$country])) {
  556. return $phone;
  557. }
  558. $dialCode = $countryData[$country]['dialCode'];
  559. if (!str_starts_with($phone, $dialCode)) {
  560. $phone = $dialCode . $phone;
  561. }
  562. return str_replace('+370+370', '+370', $phone);
  563. }
  564. private function normalizeLithuanianPhone(?string $phone): ?string
  565. {
  566. if (!$phone) {
  567. return null;
  568. }
  569. $phone = preg_replace('/^6/i', '+3706', $phone);
  570. return preg_replace('/^86/i', '+3706', $phone);
  571. }
  572. private function phoneToSearch(?string $phone): ?string
  573. {
  574. if (!$phone || strlen($phone) <= 5) {
  575. return null;
  576. }
  577. $phone = str_replace('+3706', '', $phone);
  578. $phone = str_replace('3706', '', $phone);
  579. return preg_replace('/^86/i', '', $phone);
  580. }
  581. private function normalizeEmail(?string $email): ?string
  582. {
  583. $email = trim((string) $email);
  584. return $email === '' ? null : strtolower($email);
  585. }
  586. private function saveStudentClass(FormInterface $form, RequestStack $requestStack): void
  587. {
  588. if ($form->has('class') && $form->get('class')->getData()) {
  589. $requestStack->getSession()->set('guardianRegisterClass', $form->get('class')->getData());
  590. return;
  591. }
  592. $requestStack->getSession()->set('guardianRegisterClass', null);
  593. }
  594. private function getGuardianRegisterFromSession(RequestStack $requestStack): GuardianRegister
  595. {
  596. $guardianRegister = $requestStack->getSession()->get('guardianRegister');
  597. if ($guardianRegister) {
  598. return unserialize($guardianRegister);
  599. }
  600. return (new GuardianRegister())
  601. ->setEmail(null)
  602. ->setPhone(null);
  603. }
  604. private function getRedirectType(Request $request, ?string $type): ?string
  605. {
  606. if ($type) {
  607. return null;
  608. }
  609. $redirect = $request->query->get('redirect');
  610. if ($redirect === self::TYPE_GUARDIAN) {
  611. return self::TYPE_GUARDIAN;
  612. }
  613. return $this->isStudentType($redirect) ? self::TYPE_STUDENT : null;
  614. }
  615. private function isCodeConfirmStep(string $type, int $step): bool
  616. {
  617. return ($this->isGuardianType($type) && $step === 2) || ($this->isStudentType($type) && $step === 3);
  618. }
  619. private function getCodeConfirmStep(string $type): int
  620. {
  621. return $this->isGuardianType($type) ? 2 : 3;
  622. }
  623. private function isGuardianType(string $type): bool
  624. {
  625. return $type === self::TYPE_GUARDIAN;
  626. }
  627. private function isStudentType(?string $type): bool
  628. {
  629. return in_array($type, [self::TYPE_STUDENT, self::LEGACY_TYPE_STUDENT], true);
  630. }
  631. private function getFormType(string $type): string
  632. {
  633. return $this->isStudentType($type) ? self::LEGACY_TYPE_STUDENT : $type;
  634. }
  635. private function getTemplateType(string $type): string
  636. {
  637. return $this->isStudentType($type) ? self::LEGACY_TYPE_STUDENT : $type;
  638. }
  639. private function redirectToStep(string $type, $step): Response
  640. {
  641. return $this->redirectToRoute('guardian_short_register_v2_type', [
  642. 'type' => $this->isStudentType($type) ? self::TYPE_STUDENT : $type,
  643. 'step' => $step,
  644. ]);
  645. }
  646. private function renderStep(?FormInterface $form, $step, ?string $type, ?GuardianRegister $guardianRegister = null): Response
  647. {
  648. return $this->renderForm('guardian_register/frontend/short_registration_steps_v2.html.twig', [
  649. 'form' => $form,
  650. 'step' => $step,
  651. 'type' => $type,
  652. 'guardianRegister' => $guardianRegister,
  653. ]);
  654. }
  655. private function renderStart(): Response
  656. {
  657. return $this->render('guardian_register/frontend/short_registration_steps_v2.html.twig', [
  658. 'form' => null,
  659. 'step' => 'start',
  660. 'type' => null,
  661. ]);
  662. }
  663. private function renderSuccess(RequestStack $requestStack, string $type): Response
  664. {
  665. $guardianRegister = $requestStack->getSession()->get('guardianRegister');
  666. if ($guardianRegister) {
  667. $guardianRegister = unserialize($guardianRegister);
  668. }
  669. return $this->render('guardian_register/frontend/short_registration_success.html.twig', [
  670. 'guardianRegister' => $guardianRegister,
  671. 'step' => 'end',
  672. 'type' => $this->getTemplateType($type),
  673. ]);
  674. }
  675. }