Spaces:
No application file
No application file
namespace Mautic\CampaignBundle\Executioner\Helper; | |
use Doctrine\Common\Collections\ArrayCollection; | |
use Mautic\CampaignBundle\Entity\Event; | |
use Mautic\CampaignBundle\Entity\EventRepository; | |
use Mautic\CampaignBundle\Entity\LeadEventLogRepository; | |
use Mautic\CampaignBundle\Executioner\ContactFinder\InactiveContactFinder; | |
use Mautic\CampaignBundle\Executioner\Exception\DecisionNotApplicableException; | |
use Mautic\CampaignBundle\Executioner\Scheduler\EventScheduler; | |
use Psr\Log\LoggerInterface; | |
class InactiveHelper | |
{ | |
private ?\DateTimeInterface $earliestInactiveDate = null; | |
public function __construct( | |
private EventScheduler $scheduler, | |
private InactiveContactFinder $inactiveContactFinder, | |
private LeadEventLogRepository $eventLogRepository, | |
private EventRepository $eventRepository, | |
private LoggerInterface $logger, | |
private DecisionHelper $decisionHelper | |
) { | |
} | |
/** | |
* @param ArrayCollection<int, Event> $decisions | |
*/ | |
public function removeDecisionsWithoutNegativeChildren(ArrayCollection $decisions): void | |
{ | |
/** | |
* @var int $key | |
* @var Event $decision | |
*/ | |
foreach ($decisions as $key => $decision) { | |
$negativeChildren = $decision->getNegativeChildren(); | |
if (!$negativeChildren->count()) { | |
$decisions->remove($key); | |
} | |
} | |
} | |
/** | |
* @param int $lastActiveEventId | |
* | |
* @throws \Mautic\CampaignBundle\Executioner\Scheduler\Exception\NotSchedulableException | |
*/ | |
public function removeContactsThatAreNotApplicable( | |
\DateTime $now, | |
ArrayCollection $contacts, | |
$lastActiveEventId, | |
ArrayCollection $negativeChildren, | |
Event $event | |
): void { | |
$contactIds = $contacts->getKeys(); | |
$lastActiveDates = $this->getLastActiveDates($lastActiveEventId, $contactIds); | |
$this->earliestInactiveDate = $now; | |
foreach ($contactIds as $contactId) { | |
try { | |
$this->decisionHelper->checkIsDecisionApplicableForContact($event, $contacts->get($contactId)); | |
} catch (DecisionNotApplicableException $e) { | |
$this->logger->debug($e->getMessage()); | |
$contacts->remove($contactId); | |
continue; | |
} | |
if (!isset($lastActiveDates[$contactId])) { | |
// This contact does not have a last active date so likely the event is scheduled | |
$contacts->remove($contactId); | |
$this->logger->debug('CAMPAIGN: Contact ID# '.$contactId.' does not have a last active date ('.$lastActiveEventId.')'); | |
continue; | |
} | |
$earliestContactInactiveDate = $this->getEarliestInactiveDate($negativeChildren, $lastActiveDates[$contactId]); | |
$this->logger->debug( | |
'CAMPAIGN: Earliest date for inactivity for contact ID# '.$contactId.' is '. | |
$earliestContactInactiveDate->format('Y-m-d H:i:s T').' based on last active date of '. | |
$lastActiveDates[$contactId]->format('Y-m-d H:i:s T') | |
); | |
if ($this->earliestInactiveDate < $earliestContactInactiveDate) { | |
$this->earliestInactiveDate = $earliestContactInactiveDate; | |
} | |
// If any are found to be inactive, we process or schedule all the events associated with the inactive path of a decision | |
if ($earliestContactInactiveDate > $now) { | |
$contacts->remove($contactId); | |
$this->logger->debug('CAMPAIGN: Contact ID# '.$contactId.' has been active and thus not applicable'); | |
continue; | |
} | |
$this->logger->debug('CAMPAIGN: Contact ID# '.$contactId.' has not been active'); | |
} | |
} | |
/** | |
* @return \DateTimeInterface | |
*/ | |
public function getEarliestInactiveDateTime() | |
{ | |
return $this->earliestInactiveDate; | |
} | |
public function getCollectionByDecisionId($decisionId): ArrayCollection | |
{ | |
$collection = new ArrayCollection(); | |
/** @var Event|null $decision */ | |
$decision = $this->eventRepository->find($decisionId); | |
if ($decision && !$decision->isDeleted()) { | |
$collection->set($decision->getId(), $decision); | |
} | |
return $collection; | |
} | |
/** | |
* @throws \Mautic\CampaignBundle\Executioner\Scheduler\Exception\NotSchedulableException | |
*/ | |
public function getEarliestInactiveDate(ArrayCollection $negativeChildren, \DateTimeInterface $lastActiveDate): ?\DateTimeInterface | |
{ | |
$earliestDate = null; | |
foreach ($negativeChildren as $event) { | |
$executionDate = $this->scheduler->getExecutionDateTime($event, $lastActiveDate); | |
if (!$earliestDate || $executionDate < $earliestDate) { | |
$earliestDate = $executionDate; | |
} | |
} | |
return $earliestDate; | |
} | |
/** | |
* @return array<string, \DateTimeInterface>|null | |
*/ | |
private function getLastActiveDates($lastActiveEventId, array $contactIds): ?array | |
{ | |
// If there is a parent ID, get last active dates based on when that event was executed for the given contact | |
// Otherwise, use when the contact was added to the campaign for comparison | |
if ($lastActiveEventId) { | |
return $this->eventLogRepository->getDatesExecuted($lastActiveEventId, $contactIds); | |
} | |
return $this->inactiveContactFinder->getDatesAdded(); | |
} | |
} | |