src/Component/GoogleCloud/TalentSolution/EventListener/EventListener.php line 46

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Component\GoogleCloud\TalentSolution\EventListener;
  4. use App\Component\GoogleCloud\TalentSolution\Client\AbstractClient;
  5. use App\Component\GoogleCloud\TalentSolution\Client\CompanyClient;
  6. use App\Component\GoogleCloud\TalentSolution\Client\VacancyClient;
  7. use App\Component\GoogleCloud\TalentSolution\Handler\VacancyHandler;
  8. use App\Entity\Company;
  9. use App\Entity\Repository\VacancyRepository;
  10. use App\Entity\Vacancy;
  11. use App\Event\VacancyEvent;
  12. use App\EventListener\FeatureFlagListener;
  13. use App\Repository\CompanyRepository;
  14. use Doctrine\ORM\EntityManagerInterface;
  15. use Exception;
  16. use Flagception\Manager\FeatureManagerInterface;
  17. use Google\ApiCore\ApiException;
  18. use Google\ApiCore\ValidationException;
  19. use Google\Cloud\Talent\V4beta1\Job;
  20. use Psr\Log\LoggerInterface;
  21. use Symfony\Component\Stopwatch\Stopwatch;
  22. class EventListener
  23. {
  24.     public const GCTS_STOPWATCH_SYNC_EVENT 'gcts_stopwatch_sync_event';
  25.     protected Stopwatch $stopWatch;
  26.     /**
  27.      * GoogleCloudTalentSolutionEventListener constructor.
  28.      */
  29.     public function __construct(
  30.         private readonly EntityManagerInterface $entityManager,
  31.         private readonly VacancyClient $vacancyClient,
  32.         private readonly CompanyClient $companyClient,
  33.         private readonly LoggerInterface $logger,
  34.         private readonly FeatureManagerInterface $featureManager,
  35.         private readonly VacancyHandler $vacancyHandler,
  36.     ) {
  37.         $this->stopWatch = new Stopwatch();
  38.     }
  39.     public function onExternalIntergationImportCompleted(): void
  40.     {
  41.         if (!$this->featureManager->isActive(FeatureFlagListener::FEATURE_GOOGLE_CLOUD_TALENT_SOLUTION)) {
  42.             return;
  43.         }
  44.         if ('prod' !== $_ENV['APP_ENV']) {
  45.             $this->logger->info('Not in a prod environment, vacancies and companies will not be synchronized to Google');
  46.             return;
  47.         }
  48.         $this->stopWatch->start(self::GCTS_STOPWATCH_SYNC_EVENT);
  49.         $this->logger->info('Start sync');
  50.         // GCTS requires vacancies to have companies, syncing these is step 1
  51.         try {
  52.             $this->syncCompanies();
  53.         } catch (Exception $exception) {
  54.             $message 'Fetching GCTS company ids failed, this is a reason to stop sync. Stopping sync...';
  55.             $this->logger->error(
  56.                 $message,
  57.                 [
  58.                     'message' => $exception->getMessage(),
  59.                     'file' => $exception->getFile(),
  60.                     'line' => $exception->getLine(),
  61.                     'duration' => $this->stopWatch->stop(self::GCTS_STOPWATCH_SYNC_EVENT)->getDuration().'ms',
  62.                 ]
  63.             );
  64.             return;
  65.         }
  66.         $this->vacancyHandler->updateVacancyNames();
  67.         // If syncCompanies has finished, sync vacancies
  68.         $this->syncVacancies();
  69.         $this->logger->info(
  70.             sprintf(
  71.                 'Sync finished in %s milliseconds',
  72.                 $this->stopWatch->stop(self::GCTS_STOPWATCH_SYNC_EVENT)->getDuration()
  73.             )
  74.         );
  75.     }
  76.     public function onVacancyPersisted(VacancyEvent $vacancyEvent): void
  77.     {
  78.         if (!$this->featureManager->isActive(FeatureFlagListener::FEATURE_GOOGLE_CLOUD_TALENT_SOLUTION)) {
  79.             return;
  80.         }
  81.         if ('prod' !== $_ENV['APP_ENV']) {
  82.             $this->logger->info('Not in a prod environment, vacancies and companies will not be synchronized to Google');
  83.             return;
  84.         }
  85.         $vacancy $vacancyEvent->getVacancy();
  86.         if (!$vacancy->getCompany() instanceof Company) {
  87.             return;
  88.         }
  89.         try {
  90.             /* @var Job $gctsVacancy */
  91.             $this->companyClient->saveCompany($vacancy->getCompany());
  92.             $this->entityManager->flush();
  93.             $this->vacancyClient->saveJob($vacancy);
  94.             $this->entityManager->persist($vacancy);
  95.             $this->entityManager->flush();
  96.             $this->logger->info(
  97.                 sprintf(
  98.                     'Saved vacancy %s to GCTS after %s',
  99.                     $vacancy->getId(),
  100.                     \get_class($vacancyEvent)
  101.                 )
  102.             );
  103.         } catch (Exception $exception) {
  104.             $this->logger->error(
  105.                 sprintf(
  106.                     'Failure saving vacancy %s to GCTS after %s',
  107.                     $vacancy->getId(),
  108.                     \get_class($vacancyEvent)
  109.                 ),
  110.                 [
  111.                     'message' => $exception->getMessage(),
  112.                     'file' => $exception->getFile(),
  113.                     'line' => $exception->getLine(),
  114.                 ]
  115.             );
  116.         }
  117.     }
  118.     public function onVacancyRemoved(VacancyEvent $vacancyEvent): void
  119.     {
  120.         if (!$this->featureManager->isActive(FeatureFlagListener::FEATURE_GOOGLE_CLOUD_TALENT_SOLUTION)) {
  121.             return;
  122.         }
  123.         if ('prod' !== $_ENV['APP_ENV']) {
  124.             $this->logger->info('Not in a prod environment, vacancies and companies will not be synchronized to Google');
  125.             return;
  126.         }
  127.         $vacancy $vacancyEvent->getVacancy();
  128.         try {
  129.             $this->vacancyClient->deleteJob($vacancy);
  130.             if ($state $this->entityManager->getFilters()->isEnabled('softdeleteable')) {
  131.                 $this->entityManager->getFilters()->disable('softdeleteable');
  132.             }
  133.             $vacancy->setGoogleCloudName(null);
  134.             $this->entityManager->persist($vacancy);
  135.             $this->entityManager->flush();
  136.             if ($state) {
  137.                 $this->entityManager->getFilters()->enable('softdeleteable');
  138.             }
  139.             $this->logger->info(
  140.                 sprintf(
  141.                     'Deleted vacancy %s from GCTS after %s',
  142.                     $vacancy->getId(),
  143.                     \get_class($vacancyEvent)
  144.                 )
  145.             );
  146.         } catch (Exception $exception) {
  147.             $this->logger->error(
  148.                 sprintf(
  149.                     'Failure deleting vacancy %s from GCTS after %s',
  150.                     $vacancy->getId(),
  151.                     \get_class($vacancyEvent)
  152.                 ),
  153.                 [
  154.                     'message' => $exception->getMessage(),
  155.                     'file' => $exception->getFile(),
  156.                     'line' => $exception->getLine(),
  157.                 ]
  158.             );
  159.         }
  160.     }
  161.     private function getLogMessage(string $actionstring $objectint $count): string
  162.     {
  163.         return sprintf('Google cloud %s %s %s'$action$count$object);
  164.     }
  165.     /**
  166.      * @throws ApiException
  167.      * @throws ValidationException
  168.      * @throws \JsonException
  169.      */
  170.     private function syncCompanies(): void
  171.     {
  172.         $externalCompanyIds $this->companyClient->getCompanyIds();
  173.         /** @var CompanyRepository $companyRepo */
  174.         $companyRepo $this->entityManager->getRepository(Company::class);
  175.         $companyIds $companyRepo->getCompanyIds();
  176.         $externalSerenaCompanyIds array_map('intval'array_keys($externalCompanyIds));
  177.         $deleteableCompaniesIds array_diff($externalSerenaCompanyIds$companyIds);
  178.         $updateableCompaniesIds array_intersect($externalSerenaCompanyIds$companyIds);
  179.         $insertableCompaniesIds array_diff($companyIds$externalSerenaCompanyIds);
  180.         $this->logger->info(
  181.             $this->getLogMessage(
  182.                 'Deleting',
  183.                 'companies',
  184.                 \count($deleteableCompaniesIds)
  185.             )
  186.         );
  187.         foreach ($deleteableCompaniesIds as $deleteableCompanyid) {
  188.             $this->companyClient->deleteCompany($externalCompanyIds[$deleteableCompanyid]);
  189.         }
  190.         $gctsCompanies = [];
  191.         $this->logger->info(
  192.             $this->getLogMessage(
  193.                 'Updating',
  194.                 'companies',
  195.                 \count($updateableCompaniesIds)
  196.             )
  197.         );
  198.         $updateableCompanies $companyRepo->findBy(['id' => $updateableCompaniesIds]);
  199.         foreach ($updateableCompanies as $company) {
  200.             if (!\is_string($company->getGoogleCloudName())) {
  201.                 $company->setGoogleCloudName($externalCompanyIds[$company->getId()]);
  202.             }
  203.             $gctsCompany $this->companyClient->saveCompany($company);
  204.             $gctsCompanies[$company->getId()] = $gctsCompany?->getName();
  205.         }
  206.         $this->logger->info(
  207.             $this->getLogMessage(
  208.                 'Creating',
  209.                 'companies',
  210.                 \count($insertableCompaniesIds)
  211.             )
  212.         );
  213.         $insertableCompanies $companyRepo->findBy(['id' => $insertableCompaniesIds]);
  214.         foreach ($insertableCompanies as $company) {
  215.             $gctsCompany $this->companyClient->saveCompany($company);
  216.             $gctsCompanies[$company->getId()] = $gctsCompany?->getName();
  217.         }
  218.         $companyRepo->updateCompanyGCTSNames($gctsCompanies);
  219.     }
  220.     private function syncVacancies(): void
  221.     {
  222.         // Sync available vacancies
  223.         /** @var VacancyRepository $vacancyRepo */
  224.         $vacancyRepo $this->entityManager->getRepository(Vacancy::class);
  225.         $externalIds $this->vacancyClient->getExistingRequisitionIds();
  226.         $externalSerenaIds array_map('intval'array_keys($externalIds));
  227.         $internalIds $vacancyRepo->findVacancyIds();
  228.         $deleteableVacancies array_diff($externalSerenaIds$internalIds);
  229.         $this->logger->info(
  230.             sprintf('Deleting %s vacancies from google cloud'\count($deleteableVacancies))
  231.         );
  232.         foreach ($deleteableVacancies as $deleteableVacancyId) {
  233.             if (!\array_key_exists($deleteableVacancyId$externalIds)) {
  234.                 continue;
  235.             }
  236.             $this->vacancyClient->deleteByName($externalIds[$deleteableVacancyId]);
  237.         }
  238.         $updatableVacancies array_intersect($externalSerenaIds$internalIds);
  239.         $this->logger->info(
  240.             sprintf('Updating %s vacancies from google cloud'\count($updatableVacancies))
  241.         );
  242.         $vacancies $vacancyRepo->findBy(['id' => $updatableVacancies]);
  243.         try {
  244.             $this->vacancyClient->batchOperation($vacanciesAbstractClient::UPDATE);
  245.         } catch (Exception $e) {
  246.         }
  247.         $createVacancies array_diff($internalIds$externalSerenaIds);
  248.         $this->logger->info(
  249.             sprintf('Creating %s vacancies from google cloud'\count($createVacancies))
  250.         );
  251.         $vacancies $vacancyRepo->findBy(['id' => $createVacancies]);
  252.         $this->vacancyClient->batchOperation($vacanciesAbstractClient::CREATE);
  253.     }
  254. }