<?php
namespace App\EventSubscriber\App;
use App\Entity\ExtendedApplication\ExtendedApplication;
use App\Entity\PlatformEvent;
use App\Entity\Profile;
use App\Entity\Profile\JoboffererProfile;
use App\Entity\Profile\JobseekerProfile;
use App\Entity\UsageEvent;
use App\Entity\User;
use App\Event\ProfileEditedEvent;
use App\Event\ProfileEvent;
use App\Event\ProfilePhotoAddedEvent;
use App\Event\ProfilePhotoRemovedEvent;
use App\Service\ConversionEventService;
use App\Service\JoboffererProfileService;
use App\Service\NotificationService;
use App\Service\PlatformEventService;
use App\Service\ProfileService;
use App\Service\UsageEventService;
use App\SymfonyMessage\AskNewUserForGoogleRatingSymfonyMessage;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use FOS\ElasticaBundle\Persister\ObjectPersisterInterface;
use JanusHercules\DatawarehouseIntegration\Domain\Entity\BusinessEvent;
use JanusHercules\DatawarehouseIntegration\Domain\Service\BusinessEventDomainService;
use JanusHercules\RecurrentJobsSearch\Presentation\Services\RecurrentJobsSearchPresentationService;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Messenger\MessageBusInterface;
readonly class ProfileEventSubscriber implements EventSubscriberInterface
{
public function __construct(
private BusinessEventDomainService $businessEventDomainService,
private UsageEventService $usageEventService,
private NotificationService $notificationService,
private ConversionEventService $conversionEventService,
private ObjectPersisterInterface $recurrentJobsPersister,
private ObjectPersisterInterface $wantedJobsPersister,
private JoboffererProfileService $joboffererProfileService,
private ProfileService $profileService,
private MessageBusInterface $messageBus,
private EntityManagerInterface $entityManager,
private RecurrentJobsSearchPresentationService $recurrentJobsSearchPresentationService,
private PlatformEventService $platformEventService
) {
}
public static function getSubscribedEvents(): array
{
return [
ProfileEditedEvent::class => 'onProfileEdited',
ProfilePhotoAddedEvent::class => 'onProfilePhotoAdded',
ProfilePhotoRemovedEvent::class => 'onProfilePhotoRemoved'
];
}
/** @throws Exception */
public function onProfileEdited(ProfileEvent $event): void
{
$this->businessEventDomainService->writeNewEvent(
BusinessEvent::EVENT_TYPE_PROFILE_EDITED,
$event->getProfile()->getUser(),
null,
null,
json_encode($event->getProfile()->getId())
);
if ($event->getProfile()->isJobseeker() && $event->getProfile()->getState() === Profile::STATE_BASE) {
$this->profileService->activateHiddenWantedJobsForProfile($event->getProfile());
}
if ($event->getProfile()->isBaseProfile()) {
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_WEBDE_MAILING_FOR_NONACTIVATED_PROFILE,
0
);
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_ACTIVATION,
null,
$event->getProfile()->getUser()
);
}
if ($event->getProfile()->isJobseeker()) {
$this->notificationService->uncancelNotification(
$event->getProfile()->getUser(),
NotificationService::NOTIFICATION_TYPE_UNREAD_CONVERSATION_MESSAGES
);
$this->notificationService->uncancelNotification(
$event->getProfile()->getUser(),
NotificationService::NOTIFICATION_TYPE_UNREAD_JOBRADAR_MATCHES
);
if ($event->getProfile()->isBaseProfile()) {
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_JOBSEEKER_BASE_PROFILE
);
}
if ($event->getProfile()->isBasePlusProfile()) {
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_JOBSEEKER_BASE_PLUS_PROFILE
);
}
}
if ($event->getProfile()->isJobofferer()) {
if ($event->getProfile()->isBaseProfile()) {
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_JOBOFFERER_BASE_PROFILE
);
}
if ($event->getProfile()->isBasePlusProfile()) {
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_JOBOFFERER_BASE_PLUS_PROFILE
);
}
/** @var JoboffererProfile $profile */
$profile = $event->getProfile();
if ($profile->getAdditionalFiles()->count() > 0) {
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_PROFILE_FIELDS_JOBOFFERER_3
);
}
$this->joboffererProfileService->checkIfProfileMustBeIdentifiedAsRecruitmentAgency($profile);
}
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_JOBSEEKER_ACTIVITY
);
if (!is_null($event->getProfile()->getSelfdescription()) && $event->getProfile()->getSelfdescription() !== '') {
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_PROFILE_FIELDS_JOBSEEKER_1
);
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_PROFILE_FIELDS_JOBOFFERER_1
);
if ($event->getPriorState()['hadAboutMeBefore'] === false) {
$this->businessEventDomainService->writeNewEvent(BusinessEvent::EVENT_TYPE_ABOUT_ME_WAS_ADDED, $event->getProfile()->getUser());
}
}
if (!is_null($event->getProfile()->getDocumentFileName()) && $event->getProfile()->getDocumentFileName() !== '') {
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_PROFILE_FIELDS_JOBSEEKER_2
);
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_PROFILE_FIELDS_JOBSEEKER_4
);
if ($event->getPriorState()['hadCVBefore'] === false) {
$this->businessEventDomainService->writeNewEvent(BusinessEvent::EVENT_TYPE_CV_WAS_ADDED, $event->getProfile()->getUser());
}
}
// This will only ever apply to jobseeker because of the way we handle additional files for jobofferers, that's why this event is also handled in JoboffererProfileAdditionalFilesController
if ($event->getProfile()->getAdditionalFiles()->count() > 0 && $event->getPriorState()['hadAdditionalDocumentsBefore'] === false) {
$this->businessEventDomainService->writeNewEvent(
BusinessEvent::EVENT_TYPE_ADDITIONAL_DOCUMENT_WAS_ADDED,
$event->getProfile()->getUser()
);
}
if (!is_null($event->getProfile()->getMobilenumber()) && $event->getProfile()->getMobilenumber() !== '' && $event->getPriorState()['hadPhoneNumberBefore'] === false) {
$this->businessEventDomainService->writeNewEvent(
BusinessEvent::EVENT_TYPE_PHONE_NUMBER_WAS_ADDED,
$event->getProfile()->getUser()
);
}
if ($event->getProfile()->hasPhoto()) {
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_PROFILE_FIELDS_JOBSEEKER_3
);
$this->conversionEventService->handleConversionGoalReached(
ConversionEventService::CAMPAIGN_ID_NOTIFICATION,
NotificationService::NOTIFICATION_TYPE_MISSING_PROFILE_FIELDS_JOBOFFERER_2
);
}
// Some attributes of RecurrentJobs and WantedJobs are transitive and come from the profile of their owner
// (e.g. the zipcode).
// Thus, changes to a profile might require the index data in ES to be updated, but Elastica cannot know
// that a change in the profile zipcode requires an update of this index data, and thus, we need to explicitly
// tell Elastica.
if ($event->getProfile()->isJobseeker()) {
/** @var JobseekerProfile $profile */
$profile = $event->getProfile();
foreach ($profile->getWantedJobs() as $wantedJob) {
if ($wantedJob->isFindable()) {
$this->wantedJobsPersister->replaceOne($wantedJob);
}
}
}
if ($event->getProfile()->isJobofferer()) {
/** @var JoboffererProfile $profile */
$profile = $event->getProfile();
foreach ($profile->getRecurrentJobs() as $recurrentJob) {
if ($recurrentJob->isFindable()) {
$this->recurrentJobsPersister->replaceOne($recurrentJob);
}
}
}
if ($event->getProfile()->getState() > Profile::STATE_EMPTY && $event->getProfile()->getUser()->getCreatedVia() === User::CREATED_VIA_RECRUIT_DL_RECURRENT_JOB_LANDINGPAGE) {
/** @var ExtendedApplication|null $extendedApplication */
$extendedApplication = $this->entityManager->getRepository(ExtendedApplication::class)->findOneBy(['jobseekerProfile' => $event->getProfile()->getId()]);
if (!is_null($extendedApplication)) {
$jobseekerProfileId = $event->getProfile()->getId();
if (!$this->platformEventService->hasEventOccuredInLastNDaysForAdditionalData(
PlatformEvent::EVENT_TYPE_ASK_USER_FOR_GOOGLE_RATINGS_WHATSAPP_MESSAGE_WAS_SENT,
10,
$jobseekerProfileId
)) {
$this->platformEventService->eventHasOccurred(
PlatformEvent::EVENT_TYPE_ASK_USER_FOR_GOOGLE_RATINGS_WHATSAPP_MESSAGE_WAS_SENT,
$jobseekerProfileId
);
$this->messageBus->dispatch(
new AskNewUserForGoogleRatingSymfonyMessage($extendedApplication)
);
}
}
}
}
/** @throws Exception */
public function onProfilePhotoAdded(ProfileEvent $event)
{
$this->usageEventService->eventHasOccurredForUser(
$event->getProfile()->getUser(),
UsageEvent::EVENT_TYPE_USER_HAS_ADDED_PROFILE_PICTURE
);
$this->businessEventDomainService->writeNewEvent(
BusinessEvent::EVENT_TYPE_PROFILE_PHOTO_WAS_ADDED,
$event->getProfile()->getUser()
);
}
/** @throws Exception */
public function onProfilePhotoRemoved(ProfileEvent $event)
{
$this->usageEventService->eventHasOccurredForUser(
$event->getProfile()->getUser(),
UsageEvent::EVENT_TYPE_USER_HAS_DELETED_PROFILE_PICTURE
);
$this->businessEventDomainService->writeNewEvent(
BusinessEvent::EVENT_TYPE_PROFILE_PHOTO_WAS_DELETED,
$event->getProfile()->getUser()
);
}
}